home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Macintosh Common Lisp Related / User Contributions / Misc.sea / Misc / save-object.lisp < prev    next >
Encoding:
Text File  |  1992-04-21  |  114.5 KB  |  3,672 lines  |  [TEXT/CCL2]

  1. ;;; -*- Base: 10; Mode: LISP; Package: (DATABASE :USE LISP); Syntax: Common-Lisp -*-
  2.  
  3. ;;; SAVE-OBJECT, Version 5C, Effective Date: March, 1992.
  4. ;;; NOTE: ALLEGRO 4.0 USERS: SEE IMPORTANT INFO BELOW:
  5. ;;; Copyright (C) Kerry V. Koitzsch, 1992.
  6.  
  7. #|
  8.  
  9. The views, opinions, and/or findings contained in this document are those
  10. of the author, and should not be construed as an official position, policy,
  11. or decision of any company or other individual, unless designated by other
  12. documentation.
  13.  
  14. Permission is granted to any individual or institution to use, copy, 
  15. modify and distribute this document, provided the copyright and permission
  16. notice is maintained, intact, in all copies and supporting documentation.
  17. The author makes no representations about the suitability of the software
  18. described herein for any purpose. It is provided "as is" without express
  19. or implied warranty.
  20.  
  21. Suggestions, bugs, criticism and questions to kerry@ads.com, or 
  22. kerryk@corwin.ccs.northeastern.edu.
  23.  
  24. SAVE-OBJECT is a recursive function which writes an ASCII representation
  25. of a LISP object to a designated file.
  26.  
  27. NOTE: SAVE-OBJECT doesnt need a special LOAD function! 
  28. You can load files created by SAVE-OBJECT with the
  29. standard LOAD function:
  30.  
  31. To save:
  32.  
  33. (SAVE-OBJECT (list 10 20 30) "myfile.lisp")    ,
  34.  
  35. To restore the data in the saved list:
  36.  
  37. (LOAD "myfile.lisp")
  38.  
  39. Where the newly restored data ends up:
  40.  
  41. db:*db-input* == (LIST 10 20 30)
  42.  
  43. Objects which may be saved include:
  44.  
  45. --- symbols, keywords, characters, strings, and pathnames.
  46. --- numbers, including integer, rational, complex, and floating point.
  47. --- vectors and multi-dimensional arrays.
  48. --- objects produced by DEFSTRUCT.
  49. --- CLOS (PCL) instances, and CLOS(PCL) classes.
  50. --- hash tables.
  51. --- compiled functions, represented as (FUNCTION <function name>),
  52.     internally.
  53. --- generic functions, method objects, and class objects.
  54. --- conses and lists.
  55. --- circular conses and lists (new)
  56. --- user defined methods may be defined for arbitrary objects, such
  57.     as images.
  58. --- readtables (a kludge for now)
  59. --- CLIM objects (saved as ordinary CLOS instances)
  60.  
  61. Calling sequence for INSTANCE-DUMP-FORM:
  62. ------- -------- --- ------------------
  63.  
  64. class-slots ==> all-slotnames ==> all-slots-and-values ==>
  65. map-instance ==> get-slot-values ==> get-ordered-slot-values ==>
  66. instance-dump-form.
  67.  
  68. Tested on:
  69. ------ --
  70. Machines: Sun-4, Symbolics 3670, Mac IIfx and Mac Quadra.
  71. Versions of Symbolics Common Lisp: Genera 8.1, Genera 7.2 w/rev 4b PCL.
  72. Versions of PCL/CLOS: AAAI PCL, Victoria Day PCL, REV 4b PCL, Lucid 4.0
  73. CLOS.
  74.  
  75. Versions of MCL: 2.0b3
  76.  
  77. Versions of Allegro Common Lisp: 4.0, 4.1beta.
  78.  
  79. Note: ALLEGRO 4.0 users: the patch which fixes the defstruct slot-
  80. value problem must be installed in your 4.0 image for this code to
  81. work properly! Franz internal problem number: spr4914, patch25.fasl.
  82. See your Franz dealer to get a copy.
  83.  
  84. Versions of Lucid (Sun) Common Lisp: 4.0.
  85.  
  86. Directions:
  87. -----------
  88.  
  89. (0) SPECIAL DIRECTIONS FOR USERS OF MCL2.0f3:
  90.     ADD THE FOLLOWING LINE TO THE TOP OF YOUR FILE:
  91.     (pushnew :mcl2.0f3 *features*)
  92.  
  93. (1) Redefine the IN-PACKAGEs below to suit: they should USE CLOS or PCL,
  94. though.
  95.  
  96. In version 5a, the attribute line should be correct to 'just load' the
  97. file, even if the package database does not exist.
  98. Or, try this:
  99.  
  100. (make-package 'DATABASE :nicknames '(db) :use '(common-lisp))
  101. (in-package 'database)
  102. (shadowing-import '(setf documentation) 'database)
  103. (use-package 'clos)
  104.  
  105. If at any point an error occurs about conflicting symbols, select the
  106. proceed option which prefers the symbols in the common lisp package.
  107.  
  108. (2) After defining an appropriate package, load the file,
  109.     save-object.lisp, or its compiled version.
  110.  
  111. (3) Enter package DATABASE with (in-package 'DATABASE). You are now
  112. ready to save objects!
  113.  
  114. (4) To save an object to a file, invoke the save-object function:
  115.  
  116. (in-package 'database)
  117. (save-object (list 20 30 19.6) "my-simple-filename.lisp")
  118.  
  119. to reload the saved-object file:
  120.  
  121. (load "my-simple-filename.lisp")
  122.  
  123. The result of the load is stored in the global variable *db-input*,
  124. in the DATABASE package.
  125.  
  126. Changes from Version 4A;
  127. ------------------------
  128.  
  129. --- Attribute line is fixed for Symbolics users.
  130.  
  131. --- the ability to save CLOS instances with unbound slots: fixed the
  132.     bug where nil was installed as the slot value. (see TEST-UNBOUND-
  133.     SLOT-SAVE function)
  134.  
  135. --- the ability to save out CONSes (vs LISTS) in the appropriate
  136.     format: required modification to predicate CONS-P and %TYPE-OF.
  137.     (see TEST-CONS-SAVE function)
  138.  
  139. --- predicate %CONS-P is the internal cons predicate: EXCL uses an
  140.     internal function: the non-EXCL version uses a Common Lisp
  141.     version. Ideally one would use (LAST X 0) as in CLtl2 pg. 416,
  142.     but here i use (CDR (LAST X)).
  143.  
  144. --- Better flagged for future AKCL development.
  145.  
  146. --- Unsaveable slot bug, which screwed up slots and values returned,
  147.     is now fixed in the new mechanism using INSTANCE-SLOTNAMES.
  148.  
  149. --- Beginnings of modifications fr MCL2.0f3.
  150.  
  151. ========================================================================
  152.  
  153.  Defstruct functions used by SAVE-OBJECT:
  154.  --------- --------- ---- -- -----------
  155.  
  156.    STRUCTURE-P (x) [Function] :
  157.    Predicate, returns T if X is a structure instance.
  158.  
  159.    DEFSTRUCT-SLOT-COUNT (s) [Function] :
  160.    Returns the number of slots in a structure instance S.
  161.  
  162.    GET-SYMBOL-DEFSTRUCT-SPEC (symbol) [Function] :
  163.    Given a symbol, returns a standard defstruct spec if
  164.    SYMBOL is the name of a defined defstruct class:
  165.    NIL otherwise.
  166.  
  167.    ALLOCATE-STRUCT (type) [Function] :
  168.    Given a symbol TYPE which is the name of a defined defstruct
  169.    class, make a default instance of that class.
  170.  
  171.    FILL-STRUCT (struct) [Function] :
  172.  
  173.    GET-DEFSTRUCT-CONSTRUCTOR (s) [Function] :
  174.    Given a symbol or structure instance, return the
  175.    name of the function that can construct an instance 
  176.    of the same type as S.
  177.  
  178.    GET-DEFSTRUCT-NAME (s) [Function] :
  179.    Given a structure instance S, return the name of
  180.    that instances class.
  181.  
  182.    GET-DEFSTRUCT-TYPE (s) [Function] :
  183.    Given a symbol or structure instance S, return the
  184.    type of that structure class.
  185.  
  186.    GET-DEFSTRUCT-SLOT-SPEC (s slotname) [Function] :
  187.  
  188.    GET-DEFSTRUCT-SLOT-ACCESSOR (s slotname) [Function] :
  189.  
  190.    SET-DEFSTRUCT-SLOT-VALUE (s slotname new-value) [Function] :
  191.  
  192.    GET-DEFSTRUCT-SLOT-VALUE (s slotname) [Function]:
  193.  
  194.    GET-DEFSTRUCT-DESCRIPTION (s) [Function] :
  195.  
  196.    MAKE-DEFSTRUCT-BODY (s) [Function] :
  197.  
  198.    GET-DEFSTRUCT-SLOT-NAMES (s) [Function] :
  199.    Given a structure instance S, return a list of the
  200.    names of that instances slots, in no particular order.
  201.  
  202.    GET-SLOT-SPEC-NAMED (s name) [Function] :
  203.  
  204.    COPY-STRUCTURE (s &key (mode :shallow)) [Function] :
  205.    Analogous to the COPY-INSTANCE method. Mode may be :SHALLOW or
  206.    :DEEP : make a copy of the structure instance S.
  207.  
  208.    GET-DEFSTRUCT-SLOTS-AND-VALS (s) [Function] :
  209.  
  210.    MAKE-STRUCTURE (struct-type &rest kwd-val-pairs) [Macro] :
  211.    Analogous to MAKE-INSTANCE.
  212.  
  213.    GET-DEFSTRUCT-VALUES (s) [Function] :
  214.    Return the values of all the slots in structure instance S,
  215.    in the same order that the slot names are returned from
  216.    GET-DEFSTRUCT-SLOT-NAMES.
  217.  
  218. |#
  219.  
  220. ;;; Package engineering....
  221.  
  222. #+lucid
  223. (in-package 'DATABASE :nicknames '(DB) :use '(CLOS LISP))
  224.  
  225. #+:mcl
  226. (eval-when (load eval compile)
  227.  
  228. (unless (find-package 'database)
  229. (make-package 'database  :nicknames '(db) :use '(common-lisp)))
  230.  
  231. (in-package DATABASE) ;;;; ANSI definition of IN-PACKAGE
  232.  
  233. ;;;; Uncomment the following line if using mcl2.0f3....
  234. ;;;(PUSHNEW :mcl2.0f3 *features*)
  235. (pushnew :clos *features*) ;;; MCL has clos, but it isnt in the features list...
  236.  
  237. (unless (find-package 'clos)
  238. (make-package 'clos :use '(ccl common-lisp))) ;;; hence no cl package, either.
  239.  
  240. (when (equal (machine-instance) "Quadra")
  241.        (pushnew :quadra *features*) ;;; note that its a 68040 on features....
  242. )
  243.  
  244. (when (equal (machine-type) "Macintosh IIfx")
  245.        (pushnew :fx *features*) ;;; note that its an fx on features....
  246. )
  247. ) ;;; end of MCL eval-when...
  248. #+lispm
  249. (eval-when (load eval compile)
  250.  
  251. (multiple-value-bind (major minor status)
  252.   (sct:get-release-version)
  253. (cond ((and (equal major 7)(equal minor "2"))(pushnew :rel-7-2 *features*))
  254.       ((and (equal major 8)(member minor '("0" "1") :test #'equal))
  255.         (pushnew :rel8 *features*)
  256.         (if (equal minor "0")(pushnew :rel-8-0 *features*)
  257.         (pushnew :rel-8-1 *features*)))
  258.       (T (error "Can't deal with major release ~a, minor release ~a!" major minor))))
  259.  
  260. (when (find-package 'clos)
  261.       (pushnew :clos *features*))
  262.  
  263. (unless (find-package 'database)
  264.         (make-package 'database :nicknames '(db) :use '(clos)))
  265.  
  266. (shadowing-import '(setf documentation) 'database)
  267.  
  268. (unless (find-package 'clos)(format t "Couldnt find the CLOS package, trying to continue.~%"))
  269.  
  270. (in-package 'database :use '(LISP))
  271.  
  272. (defun UNLOCK-PKG (packagename)
  273. "Changes read-only package status to read+write, if package exists."
  274. (when (find-package packagename)
  275. (setf (si:pkg-locked (find-package packagename)) NIL)))
  276.  
  277. ) ;;; end of Symbolics eval-when. Worry about TI much later.
  278.  
  279. ;;; Initial package-building eval-when for allegro on suns.
  280.  
  281. #+excl
  282. (eval-when (load compile eval)
  283.  
  284. (setf excl:*cltl1-in-package-compatibility-p* T)
  285.  
  286. (in-package :Common-lisp-user)
  287.  
  288. (defpackage "database" (:nicknames "dbs") (:use :clos :excl :common-lisp-user))
  289.  
  290. (in-package DATABASE)
  291.  
  292. (in-package 'DATABASE)
  293.  
  294. #+allegro-v4.1
  295. (defun UNLOCK-PKG (packagename)
  296. "Changes read-only package status to read+write, if package exists."
  297. (when (find-package packagename)
  298.     (setf (excl::package-lock-fdefinitions
  299.        (find-package packagename)) NIL)))
  300.  
  301. #+allegro-v4.1
  302. (unlock-pkg 'common-lisp)
  303.  
  304. ) ;;; end of excl eval-when...
  305.  
  306. ;;; Set up correct Lucid hash-table accessors....
  307.  
  308. #+lucid
  309. (shadowing-import '(lcl::hash-table-rehash-size
  310.             lcl::hash-table-size
  311.             lcl::hash-table-test
  312.             lcl::hash-table-rehash-threshold
  313. ) 'database)
  314.  
  315. #+lucid
  316. (eval-when (load eval compile)
  317. (setf (symbol-function 'hash-table-rehash-size) #'lcl::hash-table-rehash-size)
  318. (setf (symbol-function 'hash-table-size) #'lcl::hash-table-size)
  319. (setf (symbol-function 'hash-table-test) #'lcl::hash-table-test)
  320. (setf (symbol-function 'hash-table-rehash-threshold) 
  321.       #'lcl::hash-table-rehash-threshold))
  322.  
  323. ;;; NOTE: Change the package def below if it does not suit you:
  324. ;;; make sure you USE-PACKAGE your favorite brand of CLOS or PCL, though.
  325.  
  326. #+lispm
  327. (in-package 'DATABASE :nicknames '(DB) :use '(CLOS LISP))
  328.  
  329. #+pcl
  330. (in-package 'DATABASE :nicknames '(DB) :use '(PCL LISP))
  331.  
  332. ;;; exported symbols....
  333.  
  334. ;;; Exports.
  335.  
  336. (export '(stream-fasd-form
  337.        symbol-fasd-form
  338.        readtable-fasd-form
  339.        generic-function-fasd-form
  340.        method-fasd-form
  341.        class-fasd-form
  342.        complex-fasd-form
  343.        array-fasd-form
  344.        structure-fasd-form
  345.        vector-fasd-form
  346.        compiled-function-fasd-form
  347.        instance-fasd-form
  348.        htab-fasd-form
  349.        cons-fasd-form))
  350.  
  351. (export '(*db-input*
  352.       *global-unsavable-slots*
  353.       save-object
  354.       pseudo-quote-reader
  355.       reset-symbol-counter
  356.       hash-table-size
  357.       hash-table-rehash-size
  358.       hash-table-rehash-threshold
  359.       hash-table-test
  360.       make-keyword
  361.       string-append
  362.       all-slots
  363.       all-slotnames
  364.       copy-instance
  365.       all-slots-and-values
  366.       all-values
  367.       %allocate-instance
  368.       find-generic-function
  369.       methodp
  370.       instance-p
  371.       instance-name
  372.       structure-p
  373.       get-slot-values
  374.       pushsym
  375.       list-array
  376.       coerce-2d-array
  377.       make-defstruct-body
  378.  
  379.       %make-array
  380.  
  381.       describe-htab
  382.       cons-p
  383.  
  384.       array-list-aux
  385.       set-defstruct-slot
  386.       get-defstruct-value
  387.  
  388.       makesyms
  389.       write-global-header))
  390.  
  391. (export '(*global-unsaveable-slotnames*
  392.       *save-object-system-date*)
  393. )
  394.  
  395. (export '(structure-p
  396.       defstruct-slot-count
  397.       get-symbol-defstruct-spec
  398.       allocate-struct
  399.       fill-struct
  400.       get-defstruct-constructor
  401.       get-defstruct-name
  402.       get-defstruct-type
  403.       get-defstruct-slot-spec
  404.       get-defstruct-slot-accessor
  405.       set-defstruct-slot-value
  406.           get-defstruct-slot-value
  407.       get-defstruct-slot-names
  408.       get-defstruct-values
  409.       make-structure
  410.       get-defstruct-slots-and-vals
  411.       copy-structure
  412.       get-slot-spec-named
  413.       get-defstruct-description
  414.       make-defstruct-body))
  415.  
  416. (export '(admissible-constant-p
  417.       list-of-constants-p))
  418.  
  419. (export '(quoted-symbol-dump-form
  420.       simple-list-dump-form))
  421.  
  422. (export '(get-unsaveable-slotnames 
  423.           unsaveable-slot-p
  424.       instance-slotnames
  425.       instance-slotnames-minus-unsaveables
  426.           instance-values
  427.       instance-values-minus-unsavables))
  428.  
  429. #-excl
  430. (in-package 'DATABASE)
  431.  
  432. #|
  433.  
  434. (shadow '(defun))
  435.  
  436. (defmacro DEFUN (name &rest args)
  437. `(eval-when (eval load compile)
  438.         (format t "now compiling: ~a.~%" ',name)
  439.         (lisp:defun ,name ,@args)))
  440. |#
  441.  
  442. ;;;;; Globals.
  443.  
  444. (defvar *debug-instance-storage* nil "when this one is T, status messages are printed by the CLOS instance saver to aid diagnosis of problems.")
  445.  
  446. (defvar *debug-local-bindings* nil "set this var to t to see a printout of the constructed lexical bindings as they are created.")
  447.  
  448. (defvar *supress-standard-object* T "")
  449. (defvar *save-contents-of-class-allocated-classes* NIL "")
  450.  
  451. (defvar *make-list-length-threshold* 10
  452. "any list longer than this, which has the same element throughout,
  453. is constructed with MAKE-LIST instead of (list el el el el el el....)."
  454. )
  455. (defvar *load-object-hash-table* (make-hash-table :size 50 :test #'eql)
  456. "A hash table which is filled at load time with objects restored from a
  457. file.")
  458.  
  459. (defvar *save-object-hash-table* (make-hash-table :size 50 :test #'eql)
  460. "A hash table which is filled at save time by the invokation of the
  461. save object function.")
  462.  
  463. (defvar *mode-for-set-object-var* nil "Either :load or :save, depending
  464. on the context. Used by SET-OBJECT-VAR.")
  465.  
  466. (defvar *mode-for-object-var* :save)
  467.  
  468. (defvar *global-unsaveable-slotnames* nil "")
  469.  
  470. (defvar *save-object-system-date* 
  471. "March 1992 Save Object 5 B Experimental.")
  472.  
  473. (defvar *unbound-slot-token* '%%.us.%)
  474. (defvar *debug-htab-load* t)
  475. (defvar *debug-struct-save* nil)
  476.  
  477. (defvar *seen* nil)
  478. (defvar *vars* nil)
  479. (defvar *structs-seen* nil)
  480. (defvar *struct-vars* nil)
  481. (defvar *htabs-seen* nil)
  482. (defvar *htab-vars* nil)
  483.  
  484. (defvar *arrays-seen* nil)
  485. (defvar *array-vars* nil)
  486. (defvar *vectors-seen* nil)
  487. (defvar *vector-vars* nil)
  488.  
  489. (defvar *current-htab-size* 5000)
  490. (defvar *current-htab-rehash-threshold* 65)
  491. (defvar *current-htab-rehash-size* 39)
  492. (defvar *current-htab-test* #'eql)
  493.  
  494. (defvar *pco-types* '(structure hash-table array-type-t
  495.               class instance circular-list)
  496. "A list of the type names returned by function %type-of, that
  497. are potentially circular objects (PCOs).")
  498.  
  499. (setf *pco-types* '(structure hash-table array-type-t 
  500.               class instance circular-list))
  501.  
  502. #+lucid
  503. (setf lcl::*print-structure* T) ;;;; "Prints the #S form of a defstruct when t."
  504.  
  505. (defvar *global-instance-count* 0)
  506.  
  507. (defvar *global-object-count* 0
  508.  "count of varnames made for object hashtable objects, by makevar in cache-object invokations.")
  509.  
  510. (defvar *use-default-class-initargs* nil)
  511. (defvar *unsaveable-slot-token* '%.uns.%)
  512.  
  513. ;;; --------------------------- AKCL DEFSTRUCT -----------------------------
  514.  
  515. #+akcl
  516. (eval-when (load eval compile)
  517.  
  518. (defun STRUCTURE-P (X)
  519. "Predicate: returns T if x is a structure instance!"
  520. )
  521. ) ;;; end of akcl defstruct eval-when...
  522.  
  523. ;;; --------------------------- SYMBOLICS DEFSTRUCT ------------------------
  524.  
  525. #+symbolics
  526. (eval-when (load eval compile)
  527.  
  528. (defun GET-SYMBOLS-DEFSTRUCT-SPEC (x)
  529. "for the slimebolical , this information is kept as a property."
  530. (si:get x 'si:defstruct-description))
  531.  
  532. (defun %STRUCTURE-P (x)
  533. "predicate, if symbol returns t if it names a struct."
  534. (cond ((and (symbolp x)(get-symbols-defstruct-spec x)) T)
  535.       ((structure-p x) T)
  536.       (T NIL)))
  537.  
  538. (defun FILL-STRUCT (struct vals)
  539. (loop for slotname in (get-defstruct-slotnames struct) do
  540.   (set-defstruct-value struct slotname (pop vals)))
  541.  struct)
  542.  
  543. (defun ALL-SLOTS (instance)
  544. "Gets all the slots from the instances class, whether inherited or not."
  545. (clos::class-slots (clos::class-of instance)))
  546.  
  547. (defun %CLASS-NAME (x)
  548. ""
  549. (if (instance-p x)(clos::class-name (clos::class-of x))
  550. (clos::class-name x)))
  551.  
  552. (defun GET-SUPERCLASS-NAMES (class)
  553. ""
  554. (mapcar #'clos::class-name (clos::class-direct-superclasses class)))
  555.  
  556. (defun GET-DEFSTRUCT-CONSTRUCTOR (defstruct-name)
  557. "Derived from defstruct sources genera 8.1: file:sys:sys2;struct.lisp."
  558. (si:get-defstruct-constructor-macro-name defstruct-name))
  559.  
  560. (defun GET-DEFSTRUCT-NAME (struct-instance)
  561. ""
  562. (if (typep struct-instance 'list)
  563.  (progn  (warn "~a has a type which is not parsable == ~a.~%"
  564.   struct-instance (type-of struct-instance)) nil)
  565.  (nth 10 (si:get-defstruct-description (type-of struct-instance)))))
  566.  
  567. (defun GET-DEFSTRUCT-NAME (struct-instance)
  568. ""
  569. (type-of struct-instance))
  570.  
  571. (defun GET-DEFSTRUCT-SLOT (struct-instance slotname)
  572. (let ((structure-name (get-defstruct-name struct-instance)))
  573.          (cdr (si:assq slotname (si:defstruct-description-slot-alist
  574.     (si:get-defstruct-description structure-name))))))
  575.  
  576. #+rel-7-2
  577. (defun SET-DEFSTRUCT-VALUE (struct-instance slotname value)
  578. (let ((slot (get-defstruct-slot struct-instance slotname)))
  579. (EVAL `(setf (,(first (reverse slot)) ,struct-instance) ,value))))
  580.  
  581. #+rel8
  582. (defun SET-DEFSTRUCT-VALUE (object slotname newval)
  583. "SETF (SLOT-VALUE <structure instance> '<slotname>) newval apparently
  584. works properly."
  585. (setf (slot-value object (make-sym slotname)) newval))
  586.  
  587. (defun STRUCTURE-P (X)
  588. "Predicate for structure instances --- Symbolics..."
  589. (cli::structurep x))
  590.  
  591. (setf (symbol-function 'structurep) #'structure-p)
  592.  
  593. (defun STRUCTURE-INSTANCE-P (X)
  594. "Predicate which returns t if the object is a STRUCTURE, NOT AN INSTANCE THEREOF!"
  595. (and (structurep x)(not (instance-p x))))
  596.  
  597. (defun MAKE-DEFSTRUCT-BODY (slot-names slot-values)
  598.   "makes a list of keyword value pairs appropriate for the body of a MAKE-x
  599.    defstruct invokation. note the recursive call to dump-form, which is where
  600.    all the real work happens."
  601.   (loop while (and slot-names slot-values) nconc
  602.     (list (make-keyword (pop slot-names))
  603.           (get-dump-form (pop slot-values)))
  604.               into answers finally (return answers)))
  605.  
  606. (defun GET-DEFSTRUCT-DESCRIPTION (x)
  607. (if (not (structurep x))
  608.     (progn (format t "~A is not a structure! you lose...." x)
  609.     NIL)
  610. (si:get (or (AND (ARRAYP X) (si:NAMED-STRUCTURE-SYMBOL X))
  611.                (AND (LISTP X) (SYMBOLP (CAR X)) (CAR X)))
  612.                    'si:DEFSTRUCT-DESCRIPTION)))
  613.  
  614. (defun QUOTEMEMBERS (lst)
  615. (loop for cell in lst collect `(QUOTE ,cell)))
  616.  
  617. (defun CSV ()
  618. "clear struct vars."
  619. (setf *struct-vars* nil *structs-seen* nil))
  620.  
  621. ;;; some things about this one are still bogus....
  622.  
  623. (defun GET-DEFSTRUCT-SLOTNAMES (x)
  624. ""
  625. (mapcar #'first (fourth (get-defstruct-description x))))
  626.  
  627. (defun GET-DEFSTRUCT-SLOTS-AND-VALS (x)
  628.   "given a defstruct instance, return a list of the slots and vals in that defstruct."
  629.   (let* ((desc (get-defstruct-description x))
  630.      (slot-names (get-defstruct-slotnames x))
  631.      (accessor-functions (mapcar #'(lambda (slot)
  632.                      (first (reverse slot)))
  633.                      (fourth desc)))
  634.      (slot-values (loop for acc in accessor-functions collect 
  635.                 (funcall acc x))))
  636. (get-dump-form (mapcar #'(lambda (e1 e2)(list e1 e2))
  637.          slot-names slot-values))))
  638.  
  639. (defun FORMATTED-DEFSTRUCT-SLOTS-AND-VALS (x)
  640.   (let ((initial (get-defstruct-slots-and-vals x)))
  641.     (loop for thang in initial nconc (list (make-keyword (first thang))
  642.                        (get-dump-form (rest thang))))))
  643.  
  644. (defun GET-DEFSTRUCT-SLOTS (x)
  645.   "given a defstruct instance, return a list of the slots in that defstruct (no values)."
  646.   (let* ((desc (get-defstruct-description x))
  647.      (slot-names (mapcar #'first (fourth desc))))
  648.          slot-names))
  649.  
  650. (defun STRUCTURE-SLOTD-NAME (slotd)
  651.   (first slotd))
  652.  
  653. (defun STRUCTURE-SLOTD-READER (slotd)
  654.   (second slotd))
  655.  
  656. (defun STRUCTURE-SLOTD-WRITER (slotd)
  657.   (third slotd))
  658.  
  659. (defun GET-DEFSTRUCT-SLOT-ACCESSOR (instance slotname)
  660. ""
  661. (or (first (LAST (assoc slotname (fourth (get-defstruct-description instance)))))
  662.     (read-from-string (concatenate 'string (format nil "~A" (type-of instance))
  663.                    "-" (format nil "~A" slotname)))))
  664.  
  665. (defun GET-DEFSTRUCT-VALUE (instance slotname)
  666. "Given an instance of a defstruct, and the name of some slot, return the slots value."
  667. (apply (get-defstruct-slot-accessor instance slotname)(list instance)))
  668.  
  669. (defun GET-DEFSTRUCT-VALUES (instance)
  670. ""
  671. (loop for slot in (get-defstruct-slots instance) collect
  672. (get-defstruct-value instance slot)))
  673.  
  674. (defun GET-DEFSTRUCT-TYPE (struct)
  675.   (type-of struct))
  676.  
  677. (defsetf get-defstruct-value set-defstruct-value)
  678.  
  679. (setf (symbol-function 'get-struct-slotnames-from-struct) 
  680.       #'get-defstruct-slotnames)
  681.  
  682. ) ;;; end of symbolics defstruct eval-when...
  683.  
  684. ;;; --------------------------- MCL DEFSTRUCT ------------------------------
  685.  
  686. #+:mcl
  687. (eval-when (load eval compile)
  688.  
  689. (defun GET-SYMBOLS-DEFSTRUCT-SPEC (symbol)
  690. "If the symbol names a defstruct, it returns that defstructs spec."
  691. (declare (ignore symbol))
  692. nil)
  693.  
  694. (defun FILL-STRUCT (struct vals)
  695. "Fills up the structure instance: invoked by STRUCTURE-FASD_FORM, GET-DUMP-FORM"
  696. (loop for slotname in (get-defstruct-slots struct) do
  697.   (set-defstruct-value struct slotname (pop vals)))
  698.  struct)
  699.  
  700. (defun GET-DEFSTRUCT-NAME (instance)
  701. ""
  702. (type-of instance))
  703.   
  704.   (defun GET-DEFSTRUCT-TYPE (instance)
  705. ""
  706.     (car (ccl::struct-ref instance 0)))
  707.   
  708.   (defun SET-DEFSTRUCT-VALUE (instance slotname value)
  709. ""
  710. (when (null instance)(error "set-defstruct-value got NULL instead of an instance!"))
  711.     (let* ((struct-slot-value-list (inspector::structure-slots instance))
  712.            (slotname-position (1+ (position slotname 
  713.                                             struct-slot-value-list 
  714.                                             :key #'first))))
  715. (when (null slotname-position)(error "couldnt find slotname ~a in ~a!" slotname instance))
  716.       (ccl::struct-set instance slotname-position value)))
  717.  
  718. (defun GET-DEFSTRUCT-VALUES (instance)
  719. "Return a supposedly ordered list of the defstruct instances values."
  720. (get-odds (get-defstruct-slots-and-vals instance)))
  721.   
  722.   (defun GET-DEFSTRUCT-VALUE (instance slotname)
  723.     "Given an instance of a defstruct, and the name of some slot, return the slots value."
  724.     (let* ((struct-slot-value-list (inspector::structure-slots instance))
  725.            (slotname-position (1+ (position slotname 
  726.                                             struct-slot-value-list 
  727.                                             :key #'first))))
  728.       (ccl::struct-ref instance slotname-position)))
  729.   
  730.   (defsetf get-defstruct-value set-defstruct-value)
  731.  
  732. (defun GET-DEFSTRUCT-SLOT-ACCESSOR (instance slotname)
  733.     ""
  734.     (let* ((id (GET-DEFSTRUCT-TYPE instance)))
  735.       (read-from-string (concatenate 'string (symbol-name id) "-"
  736.                      (symbol-name slotname)))))
  737.   
  738. (defun GET-DEFSTRUCT-SLOTS-AND-VALS (instance)
  739.   "Return a list of slots and values" ;Note that slots are not keyword names
  740.   (labels ((interlock-lists (list1 list2 &optional interlocked-list)
  741.                             (if (and list1 list2)
  742.                               (cons (car list1) 
  743.                                     (cons (car list2) 
  744.                                           (interlock-lists (rest list1)
  745.                                                            (rest list2)
  746.                                                            interlocked-list)))
  747.                               interlocked-list)))
  748.     (let* ((struct-slot-value-list (inspector::structure-slots instance))
  749.            (slot-list (mapcar #'first struct-slot-value-list))
  750.            (vals-list '()))
  751.       (dotimes (i (length slot-list))
  752.         (push (ccl::struct-ref instance (1+ i)) vals-list))
  753.       (setf vals-list (nreverse vals-list))
  754.       (interlock-lists slot-list vals-list))))
  755.  
  756. (defun GET-DEFSTRUCT-SLOTS (instance)
  757.   "Return a list of slots" ;Note that slots are not keyword names
  758.   (let* ((struct-slot-value-list (inspector::structure-slots instance)))
  759.     (mapcar #'first struct-slot-value-list)))
  760.  
  761. (setf (symbol-function 'get-struct-slotnames-from-struct) #'get-defstruct-slots)
  762.  
  763. (defun BUILTIN-CLASS-p (X)
  764. "Predicate to determine whether a class object is a built-in class: this should be the generic definition of this one."
  765. (typep x 'built-in-class))
  766.  
  767. ) ;;; end of MCl defstruct eval-when...
  768.  
  769. ;;; --------------------------- LUCID DEFSTRUCT ----------------------------
  770.  
  771. #+lucid
  772. (eval-when (load eval compile)
  773.  
  774. (defun COMPILED-FUNCTION-DUMP-FORM (X)
  775. "dump form for hashmark-quote e.g. (FUNCTION name) forms."
  776.   `(function ,(get-compiled-function-name x)))
  777.  
  778. (defun FUNCTION-NAME (x)
  779. "The 1th slot of the procedure struct is the function name in Lucid 4.0.
  780.  i.e. SYS:PROCEDURE-SYMBOL <X>. SYS:PROCEDURE-SYMBOL is a constant, representing the
  781. index to the function name within the procedures slots. (see wizard doc for 4.0 lucid."
  782. (when (sys:procedurep x)(sys:procedure-ref x SYS:PROCEDURE-SYMBOL)))
  783.  
  784. (defun GET-COMPILED-FUNCTION-NAME (compiled-function)
  785. ""
  786. (function-name compiled-function))
  787.  
  788. ;;; Long-list functions for Lucid.
  789.  
  790. (defun LONG-LIST-DUMP-FORM (instance)
  791. `(nconc ,@(make-list-forms (partition-long-list instance))))
  792.  
  793. (defun MAKE-LIST-FORMS (lists)
  794.   (loop for list in lists collect (get-dump-form list)))
  795.  
  796. (defun PARTITION-LONG-LIST (long-list &optional (limit 512))
  797. "Some LISPs have a limit on the number of list components: this function partitions a
  798.  list longer than the supplied limit appropriately for saving to file."
  799. (loop while long-list collect
  800.       (loop for count from 0 to (- limit 2) while long-list
  801.         collect (pop long-list))))
  802.  
  803. (defun GET-DEFSTRUCT-CONSTRUCTOR (name)
  804. "Extracts the name of the constructor function from the instance name."
  805. (third (multiple-value-list (system::defstruct-info name))))
  806.  
  807. (defun STRUCTURE-P (x)
  808. "Predicate to determine if something is a structure instance:
  809.  NOTE: there is overlap of types in Lucid, in this case hash tables."
  810.   (and (typep x 'structure)
  811.        (NOT (VECTORP X))
  812.        (not (hash-table-p x))
  813.        (not (typep x 'simple-vector))
  814.        (not (typep x 'simple-array))
  815.         (not (and (arrayp x)(> (array-rank x) 1)))))
  816.  
  817. #+pcl
  818. (defun STRUCTURE-TYPE-P (type)
  819.   (let ((s-data (gethash type lucid::*defstructs*)))
  820.  (or (and s-data (eq 'structure (system::structure-ref s-data 1 'defstruct)))
  821.     (eq pcl::*structure-type* type))))
  822.  
  823. (defun STRUCTURE-SLOTD-NAME (slotd)
  824.   (first slotd))
  825.  
  826. (defun STRUCTURE-SLOTD-READER (slotd)
  827.   (second slotd))
  828.  
  829. (defun STRUCTURE-SLOTD-WRITER (slotd)
  830.   (third slotd))
  831.  
  832. (defun SET-DEFSTRUCT-VALUE (instance slotname value)
  833. (EVAL `(setf (,(get-defstruct-slot-accessor instance slotname) ,instance)
  834.          ',value)))
  835.  
  836. (defun GET-DEFSTRUCT-VALUE (instance slotname)
  837. "Given an instance of a defstruct, and the name of some slot, return the slots value."
  838. (apply (get-defstruct-slot-accessor instance slotname)(list instance)))
  839.  
  840. (defsetf get-defstruct-value set-defstruct-value)
  841.  
  842. (defun GET-DEFSTRUCT-SLOT-LOCATION (i name)
  843. (position name (nreverse (get-defstruct-slotnames i))))
  844.  
  845. (defun GET-DEFSTRUCT-SLOT-ACCESSOR (instance slotname)
  846. ""
  847. (let* ((id (type-of instance))
  848.        (answer nil))
  849.   (multiple-value-bind (a accessor b c d)
  850.   (system:defstruct-slot-info id 
  851.       (get-defstruct-slot-location instance slotname))
  852.   a b c d
  853.  (setf answer accessor)
  854. answer)))
  855.  
  856. (defun FILL-STRUCT (struct vals)
  857. (loop for slotname in (get-defstruct-slotnames struct) do
  858.   (set-defstruct-value struct slotname (pop vals)))
  859.  struct)
  860.  
  861. (defun GET-DEFSTRUCT-SLOTS-AND-VALS (i)
  862. (loop for name in (get-defstruct-slotnames i) collect
  863.            (cons name (get-defstruct-value i name))))
  864.  
  865. (defun GET-DEFSTRUCT-VALUES (s)
  866. ""
  867. (loop for name in (get-defstruct-slotnames s) collect
  868.  (get-defstruct-value s name)))
  869.  
  870. (defun GET-DEFSTRUCT-SLOTNAMES (i)
  871.   (let ((id (type-of i)))
  872.   (multiple-value-bind (indices a b c)
  873.    (system:defstruct-info ID)
  874.       (declare (ignore a b c))
  875.       (let ((answers nil))
  876.     (dotimes (count indices answers)
  877.       (multiple-value-bind (name d value e f)
  878.           (system:defstruct-slot-info ID count)
  879.           (declare (ignore value d e f))
  880.           (push name answers)
  881.           answers))))))
  882.  
  883. (setf (symbol-function 'get-struct-slotnames-from-struct) #'get-defstruct-slotnames)
  884.  
  885. (defun %STRUCTURE-P (symbol)
  886. ""
  887. (system:defstruct-info symbol))
  888.  
  889. (defun %CLASS-NAME (class-object)
  890. ""
  891. (clos::class-name class-object))
  892.  
  893. (defun GET-DEFSTRUCT-TYPE (x)
  894. (type-of x))
  895.  
  896. (defun GET-DEFSTRUCT-NAME (x)
  897. (type-of x))
  898.  
  899. ) ;;; end of lucid defstruct eval-when...
  900.  
  901. ;;; --------------------------- ALLEGRO DEFSTRUCT --------------------------
  902.  
  903. #+excl
  904. (eval-when (load eval compile)
  905.  
  906. (defun GET-DEFSTRUCT-CONSTRUCTOR (instance)
  907. ""
  908. (if (symbolp instance)
  909. (debug::struct-constructor instance)))
  910.  
  911. (defun  GET-SLOT-NAMED (instance name)
  912. ""
  913. (dolist (x (%get-defstruct-slots instance))
  914.   (when (equal name (slot-value x 'excl::name))
  915.         (return-from get-slot-named x))))
  916.  
  917. (defun GET-DEFSTRUCT-SLOT-ACCESSOR (instance slotname)
  918. ""
  919. (when (null instance)(error "~a was not a structure instance!" instance))
  920. (slot-value (get-slot-named instance slotname) 'excl::accessor))
  921.  
  922. (defun SET-DEFSTRUCT-VALUE (struct slotname value)
  923. (setf (slot-value struct slotname) value))
  924.  
  925. #+allegro-v4.1
  926. (defun %STRUCTURE-P (x)
  927. "Predicate returns T if X is an instance of the STRUCTURE-CLASS (CLOS)"
  928. (cond ((and (symbolp x)(find-class x nil)
  929.         (equal (class-name (find-class x)) 'clos::structure-class)) T)
  930.       ((equal (instance-name  (find-class (type-of x) nil))
  931.           'clos::structure-class) T)
  932.       (T NIL)))
  933.  
  934. #+allegro-v4.0
  935. (defun %STRUCTURE-P (x)
  936. "Predicate returns T if X is an instance of the STRUCTURE-CLASS (CLOS)"
  937. (cond ((and (symbolp x)(find-class x nil)
  938.         (equal (class-name (find-class x)) 'clos::structure-object)) T)
  939.       ((equal (instance-name  (find-class (type-of x) nil))
  940.           'clos::structure-object) T)
  941.       (T NIL)))
  942.  
  943. (defun GET-DEFSTRUCT-TYPE (s)
  944. "given defstruct instance s, return type of s."
  945. (excl::structure-ref s 0))
  946.  
  947. (defun GET-DEFSTRUCT-DESCRIPTION (defstruct-name)
  948. "Given name, return description object."
  949. (nassoc 'excl::%structure-definition (symbol-plist defstruct-name)))
  950.  
  951. (defun GET-DEFSTRUCT-SLOTS (description)
  952. "Given defstruct description, return slot objects."
  953. (excl::structure-ref description 3))
  954.  
  955. (defun GET-DEFSTRUCT-NAME (s)
  956. "Given structure instance S, return the name of defstruct class."
  957. (slot-value s 'excl::name))
  958.  
  959. (defun %GET-DEFSTRUCT-SLOTS (instance)
  960. ""
  961. (get-defstruct-slots 
  962.  (get-defstruct-description
  963.   (get-defstruct-type instance))))
  964.  
  965. (defuN GET-STRUCT-SLOTNAMES-FROM-STRUCT (struct)
  966. (get-defstruct-slotnames (get-defstruct-slots
  967.  (get-defstruct-description (get-defstruct-type struct)))))
  968.  
  969. (defun GET-DEFSTRUCT-SLOTNAMES (slot-list)
  970. "Given list of slot objects, return slotnames as keywords."
  971. (mapcar #'make-keyword (mapcar #'(lambda (x)(excl::structure-ref x 1))
  972.                    slot-list)))
  973.  
  974. (defun %GET-DEFSTRUCT-SLOTNAMES (slot-list)
  975. "Given list of slot objects, return slotnames as symbols."
  976. (if (listp slot-list)
  977.  (mapcar #'(lambda (x)(excl::structure-ref x 1)) slot-list)
  978. (let ((the-ones    (get-defstruct-slots (get-defstruct-description
  979.                        (get-defstruct-type slot-list)))))
  980. (mapcar #'get-defstruct-name
  981.     (if (listp the-ones) the-ones (list the-ones))))))
  982.  
  983. (defun DEFSTRUCT-SLOT-COUNT (instance)
  984. ""
  985. (length (delete nil (get-defstruct-slotnames
  986.               (get-defstruct-slots 
  987.             (get-defstruct-description
  988.               (get-defstruct-type instance)))))))
  989.  
  990. (defun %%GET-DEFSTRUCT-SLOTNAMES (instance)
  991. (get-struct-slotnames-from-struct instance))
  992.  
  993. (defun GET-DEFSTRUCT-VALUES (instance)
  994. (let* ((slotnames (%%get-defstruct-slotnames instance))
  995.        (length (length slotnames))
  996.        (answers nil))
  997.     (dolist (slot slotnames (nreverse answers))
  998.    (push (get-defstruct-value instance slot) answers))
  999. (nreverse answers)))
  1000.  
  1001. (defun GET-DEFSTRUCT-SLOTS-AND-VALS (instance)
  1002. ""
  1003. (let* ((type (get-defstruct-type instance))
  1004.        (desc (get-defstruct-description type))
  1005.        (slots (get-defstruct-slots desc))
  1006.        (slotnames (DELETE NIL (get-defstruct-slotnames slots)))
  1007.        (len (length slotnames))
  1008.        (answers nil)
  1009.        (values (get-defstruct-values instance)))
  1010. (dotimes (count (1- len) answers)
  1011. (setf answers (append answers (list (nth count slotnames)
  1012. (get-dump-form (nth count values))))))))
  1013.  
  1014. (defun GET-DEFSTRUCT-VALUE (instance slotname)
  1015. (slot-value instance (make-sym slotname)))
  1016.  
  1017. (defun STRUCTUREP (x)
  1018. "Predicate to test whether some object is a structure instance."
  1019. (excl::structurep x))
  1020.  
  1021. (defun STRUCTURE-P (X)
  1022. "Predicate: returns T if x is a structure instance!"
  1023. (structurep x))
  1024.  
  1025. ) ;;; end of allegro defstruct eval-when...
  1026.  
  1027. ;;; Predicates.
  1028. ;;; Lists of 'admissible constants': non-structured constants.
  1029.  
  1030. (defun ADMISSIBLE-CONSTANT-P (X)
  1031. "Predicate: returns T if x is symbol, number, or keyword."
  1032. (or (stringp x)
  1033.     (null x)
  1034.     (equal x T)
  1035.     (pathnamep x)
  1036.     (numberp x)
  1037.     (keywordp x)
  1038.     (characterp x)))
  1039.  
  1040. (defun SIMPLE-LIST-P (X)
  1041. "Predicate: returns t if every element of a list X is an
  1042. admissible constant."
  1043. (and (not (cons-p x))
  1044.      (listp x)
  1045.      (not (circular-list-p X))
  1046.      (every #'admissible-constant-p x)))
  1047.  
  1048. (defun LIST-TYPE (X)
  1049.   (cond ((not (listp x))
  1050.      (format t "error: ~a is not a list~%" x))
  1051.     ((cons-p x) 'cons)
  1052.     ((simple-list-p x) 'simple)
  1053.     ((quoted-list-p x) 'quoted)
  1054.     (T 'ordinary)))
  1055.  
  1056. ;;; Vendor-independent defstruct functions.
  1057.  
  1058. (defun MAPSTRUCT (fun struct &key concat modify)
  1059. "Iterator for defstruct instances."
  1060. (let ((answers nil))
  1061. (dolist (slotname (get-struct-slotnames-from-struct struct) struct)
  1062. (when concat (push (funcall fun slotname (get-defstruct-value struct slotname))
  1063.            answers))
  1064. (when modify  (set-defstruct-value struct slotname
  1065.       (funcall fun slotname
  1066.       (get-defstruct-value struct slotname)))))
  1067. (if modify struct (nreverse answers))))
  1068.  
  1069. (defmacro MAKE-STRUCTURE (name &rest kwd-val-pairs)
  1070. "Macro analogous to make-instance, but for bona fide structures."
  1071. `(funcall (get-defstruct-constructor ,name) ,@kwd-val-pairs))
  1072.  
  1073. (defun %FILL-STRUCT (struct &rest vals)
  1074. "vals was quoted....and was comma atsign before, now just comma"
  1075. (EVAL `(fill-struct ,struct ',@vals)))
  1076.  
  1077. (defun MAKE-DEFSTRUCT-VALUES (struct)
  1078. "WAS CDR of the GET-DUMP-FORM before."
  1079. `(,@(get-defstruct-values struct)))
  1080.  
  1081. #-(or excl lucid)
  1082. (defun STRUCTURE-DUMP-FORM (instance)
  1083. "Independent of vendor: make-defstruct-values was UNquoted."
  1084. `(fill-struct ,(get-instance-label instance)
  1085.            (LIST ,@(get-defstruct-values instance))))
  1086.  
  1087. #+allegro-v4.0
  1088. (defun STRUCTURE-DUMP-FORM (instance)
  1089. "Independent of vendor: make-defstruct-values was UNquoted."
  1090. `(fill-struct ,(get-instance-label instance)
  1091.            (LIST ,@(get-defstruct-values instance))))
  1092.  
  1093. #+(or lucid allegro-v4.1)
  1094. (defun STRUCTURE-DUMP-FORM (instance)
  1095. "in version 4.1 allegro, treat structure instances just like clos instances!"
  1096.  `(fill-instance ,(get-instance-label instance)
  1097.          (LIST ,@(get-ordered-slot-values instance))))
  1098.  
  1099. #-excl
  1100. (defun FILL-STRUCT (struct vals)
  1101. "Fills the structure instance struct with the values vals."
  1102. (dolist (slotname (get-defstruct-slotnames struct) struct)
  1103.   (set-defstruct-value struct slotname (pop vals)))
  1104.  struct)
  1105.  
  1106. #+excl
  1107. (defun FILL-STRUCT (struct vals)
  1108. "Fills the structure instance struct with the values vals."
  1109. (dolist (slotname (%get-defstruct-slotnames struct) struct)
  1110.   (set-defstruct-value struct slotname (pop vals)))
  1111.  struct)
  1112.  
  1113. (defun ALLOCATE-STRUCT (name)
  1114. "Function to allocate the empty husk of a defstruct."
  1115. (apply (get-defstruct-constructor name) nil))
  1116.  
  1117. ;;; Dump forms.
  1118.  
  1119. (defun CONSTANT-DUMP-FORM (instance)
  1120. "Anything which evals to itself (aside from structured objects),
  1121.  can be written as is."
  1122. instance)
  1123.  
  1124. (defun COMPLEX-DUMP-FORM (instance)
  1125. "Dumps anything which is a complex number."
  1126. `(COMPLEX ,(get-dump-form (REALPART instance))
  1127.       ,(get-dump-form (IMAGPART instance))))
  1128.  
  1129. (defun QUOTED-SYMBOL-DUMP-FORM (instance)
  1130. "Dump form for a quoted symbol."
  1131. `(QUOTE ,(second instance)))
  1132.  
  1133. (defun SIMPLE-LEX-LIST-P (X)
  1134. (and (not (cons-p x))
  1135.      (listp x)
  1136.      (not (circular-list-p x))
  1137.      (every #'(lambda (e)
  1138.              (or (special-marker-p e)
  1139.                  (admissible-constant-p e)))
  1140.              x)))
  1141.  
  1142. (defun SIMPLE-LIST-DUMP-FORM (instance)
  1143. "Dump form for lists of admissible cnstants."
  1144. `(LIST ,@instance))
  1145.  
  1146. (defun DEFSTRUCT-DUMP-FORM (instance)
  1147. "Vendor independent!"
  1148. `(fill-struct ,(get-instance-label instance)
  1149.           ',(get-defstruct-values instance)))
  1150.  
  1151. (defun REGULAR-FUNCTION-DUMP-FORM (instance)
  1152. ""
  1153. `(FUNCTION ,instance))
  1154.  
  1155. ;;; Lucid is the only one that has a list length limit.
  1156.  
  1157. #-lucid
  1158. (eval-when (load eval compile)
  1159.  
  1160. (defun LONG-LIST-DUMP-FORM (instance)
  1161. ""
  1162. (list-dump-form instance))
  1163.  
  1164. ) ;;; long-list eval-when.
  1165.  
  1166. (defun LIST-DUMP-FORM (instance)
  1167. ""
  1168. `(LIST ,@(mapcar #'(lambda (thing)
  1169.              (get-dump-form thing))
  1170.          instance)))
  1171.  
  1172. ;;; Vendor independent, PCL/CLOS independent CLOS functions.
  1173.  
  1174. (defun PAIR-SLOTNAMES (instance)
  1175. "Makes an alist of the slotnames with their 'stripped' values."
  1176. (let ((slots (all-slotnames instance)))
  1177.   (pairlis (mapcar #'strip-package slots) slots)))
  1178.  
  1179. (defun FIND-PACKAGED-SLOTNAME (instance stripped)
  1180.   "Given the slotname WITHOUT package, find the slotname WITH package."
  1181. (let ((choices (pair-slotnames instance)))
  1182.   (rest (assoc stripped choices :test #'equal))))
  1183.  
  1184. (defun SLOT-VALUE-ANY (instance stripped)
  1185. "Find the value of the real slot given the stripped name."
  1186. (let ((slotname (find-packaged-slotname instance stripped)))
  1187.   (when slotname (if (slot-boundp instance slotname)
  1188.              (slot-value instance slotname)
  1189.              *unbound-slot-token*))))
  1190.  
  1191. (defun GET-UNSAVEABLE-SLOTNAMES (instance)
  1192. "Returns a list of the slotnames in instance, or the slotnames
  1193.  in the class of instance, which have been marked as unsaveable,
  1194.  appended to the list of *global-unsaveable-slotnames*"
  1195. (append (copy-list *global-unsaveable-slotnames*)
  1196.     (slot-value-any instance 'unsaveable)))
  1197.  
  1198. (defun UNSAVEABLE-SLOT-P (slot instance)
  1199. "Predicate returns t if the slotname SLOT is marked as USAVEABLE
  1200. for instances of the type of instance."
  1201. (or (member slot *global-unsaveable-slotnames* :test #'equal)
  1202.     (member slot (get-unsaveable-slotnames instance) :test #'equal)))
  1203.  
  1204. ;;; ROW MAJOR AREF --- ACL doesnt have it, Genera has it in package FCL....
  1205.  
  1206. ;;; lucid has row-major-aref, no problem.
  1207.  
  1208. #+(or rel-8-0 rel-8-1)
  1209. (shadowing-import '(future-common-lisp:row-major-aref) 'database)
  1210.  
  1211. #-(or lispm rel-8-0 rel-8-1 lucid)
  1212. (when (not (fboundp 'row-major-aref))
  1213. (pushnew :need-row-major-aref *features*))
  1214.  
  1215. ;;; lispm has it.
  1216.  
  1217. #-lispm
  1218. (eval-when (load eval compile)
  1219.  
  1220. #+need-row-major-aref 
  1221. (defun ROW-MAJOR-AREF (array index)
  1222. "We have to define this, as Franz does not implement RMA pg. 450 CLtL2.
  1223.  NOTE: Neither does Symbolics."
  1224. (aref (make-array (array-total-size array)
  1225.           :displaced-to array
  1226.           :element-type (array-element-type array))
  1227.       index))
  1228.  
  1229. #+need-row-major-aref
  1230. (defun ROW-MAJOR-SETA (array index newval)
  1231. "so we can defsetf row-major-aref!"
  1232. (setf (aref (make-array (array-total-size array)
  1233.             :displaced-to array
  1234.             :element-type (array-element-type array))
  1235.         index) newval))
  1236.  
  1237. #+need-row-major-aref
  1238. (defsetf row-major-aref row-major-seta)
  1239.  
  1240. ) ;;; eval-when....
  1241.  
  1242. #+ignore
  1243. (defun GET-INSTANCE-LABEL (instance)
  1244. ""
  1245. (let* ((lists (case (%type-of instance)
  1246.                 (INSTANCE (list *seen* *vars*))
  1247.                 (STRUCTURE (list *structs-seen* *struct-vars*))
  1248.                 (HASH-TABLE (list *htabs-seen* *htab-vars*))
  1249.                 (otherwise (error "Couldnt parse ~a, of type ~a!"
  1250.                                   instance (type-of instance))))))
  1251.   (let* ((instance-list (first lists))
  1252.          (var-list (second lists))
  1253.          (where (position instance instance-list :test #'equal)))
  1254.     (when (null where)(error "~a was not on the seen list!" instance))
  1255. (nth where var-list))))
  1256.  
  1257. (defun GET-INSTANCE-LABEL (instance)
  1258. ""
  1259. (let* ((lists (case (%type-of instance)
  1260.                 (INSTANCE (list *seen* *vars*))
  1261.                 (STRUCTURE (list *structs-seen* *struct-vars*))
  1262.                 (HASH-TABLE (list *htabs-seen* *htab-vars*))
  1263.                 (otherwise (error "Couldnt parse ~a, of type ~a!"
  1264.                                   instance (type-of instance))))))
  1265.   (let* ((instance-list (first lists))
  1266.          (var-list (second lists))
  1267.          (where (position instance instance-list :test #'equal)))
  1268. (if (null where)
  1269. (progn (format t "~a was not on the seen list!, creating!~%" instance)
  1270. (case (%type-of instance)
  1271. (STRUCTURE
  1272. (return-from get-instance-label
  1273.  (allocate-struct (get-defstruct-type instance))))))
  1274. (return-from get-instance-label  (nth where var-list))))))
  1275.     
  1276. (defun DO-VAR-TYPE-CELLS (vars insts)
  1277. ""
  1278. (mapcar #'(lambda (a b)(list a b))
  1279. vars insts))
  1280.  
  1281. (defun MAPAPPEND (fun &rest args)
  1282. "From the MOP book!"
  1283. (if (some #'null args)
  1284.     ()
  1285.   (append (apply fun (mapcar #'car args))
  1286.       (apply #'mapappend fun (mapcar #'cdr args)))))
  1287.  
  1288. (defun ALL-INSTANCE-LIST-P (x)
  1289. "Predicate for a list containing only instances!"
  1290. (and (listp x) (every #'instance-p x)))
  1291.  
  1292. (defun MAKE-VAR-TYPE-CELLS (vars insts &optional plists samep)
  1293. "An auxilary function for MAKE-LET-FORM..."
  1294. (let ((htab-plist (if samep (mapcar #'get-dump-form (first plists))))
  1295.       (count -1))
  1296. (mapappend
  1297.      #'(lambda (cell)
  1298.          (incf count)
  1299.          (list (list (first cell)
  1300.                      (append
  1301.              (list '%allocate-instance 
  1302.                `(QUOTE ,(instance-name (second cell))))
  1303.                         (if samep htab-plist
  1304.                   (mapcar #'get-dump-form
  1305.                       (nth count plists)))))))
  1306.       (do-var-type-cells vars insts))))
  1307.  
  1308. (defun SAMESET (l1 l2 &key (test #'equal))
  1309. "predicate, returns t if the two sets contain the same elements."
  1310. (and (subsetp l1 l2 :test test)(subsetp l2 l1 :test test)))
  1311.  
  1312. (defun SAME-KEYWORDS-P (p1 p2)
  1313. "Predicate:"
  1314. (if (or (not (listp p1))(not (listp p2))) nil
  1315. (sameset (get-evens p1)(get-evens p2))))
  1316.  
  1317. (defun MAPPLIST (fun x)
  1318. "From the MOP book!"
  1319. (if (null x) nil (cons (funcall fun (first x)(second x))
  1320.                (mapplist fun (cddr x)))))
  1321.  
  1322. (defun SAME-PLIST-VALUES-P (p1 p2)
  1323. "Use mapplist from the MOP book!"
  1324. (let ((kwds1 (get-evens p1))
  1325.       (kwds2 (get-evens p2)))
  1326. (if (not (sameset kwds1 kwds2))
  1327.     nil
  1328. (dolist (kwd kwds1 T)
  1329.    (when (not (equal (getf p1 kwd)(getf p2 kwd))) (return nil))))))
  1330.  
  1331. (defun UNORDERED-PLIST-EQUAL (p1 p2)
  1332. "predicate to tell if plist keywords & values are equal,
  1333.  regardless of attribute pair ordering."
  1334. (and (same-keywords-p p1 p2)(same-plist-values-p p1 p2)))
  1335.  
  1336. (defun ALL-HTAB-PLISTS-SAMEP (htab-plist-list)
  1337. "Predicate: does set equality on plists."
  1338. (every #'(lambda (plist)(unordered-plist-equal plist
  1339.                  (first htab-plist-list)))
  1340.        (rest htab-plist-list)))
  1341.  
  1342. (defun MAKE-HTAB-PLIST (htab)
  1343. "makes a plist for a hash tables inner attributes!"
  1344. (list :size (hash-table-size htab)
  1345.       :rehash-size (hash-table-rehash-size htab)
  1346.       :test (hash-table-test htab)
  1347.       :rehash-threshold (hash-table-rehash-threshold htab)))
  1348.  
  1349. (defun MAKE-HTAB-PLISTS (list-o-htabs)
  1350. "takes a list of htabs: checks to see if the plists are the same,
  1351. multiple value return of the attribute plist(s), and whether they
  1352. are the same (T or NIL)."
  1353. (let ((answers nil)(new-plist nil)) 
  1354. (dolist (htab list-o-htabs answers)
  1355.  (setf new-plist (make-htab-plist htab))
  1356.  (push new-plist answers))
  1357. (let ((samep (all-htab-plists-samep list-o-htabs)))
  1358. (if samep (values (list (first answers)) T)
  1359.   (values answers NIL)))))
  1360.  
  1361. (defun MAKE-ILIST-VAR-TYPE-CELLS (to-be-saved-list)
  1362. (delete nil (make-var-type-cells *vars* *seen*)))
  1363.  
  1364. (defun MAKE-LIST-VAR-TYPE-CELLS (to-be-saved-list)
  1365. "SEQUENCES need the whole ball of wax."
  1366. (declare (ignore to-be-saved-list))
  1367. (multiple-value-bind (plists samep)
  1368. (make-htab-plists *htabs-seen*)
  1369. (let* ((insts (make-var-type-cells *vars* *seen*))
  1370.        (structs (make-var-type-cells *struct-vars* *structs-seen*))
  1371.        (htabs (make-var-type-cells *htab-vars* *htabs-seen*
  1372.                    plists samep))
  1373.        (end-result (NCONC insts structs htabs)))
  1374. (when *debug-local-bindings* (format t "~%~A~%" end-result))
  1375.        (delete nil end-result))))
  1376.  
  1377. (defun MAKE-LET-FORM (object &optional other-code)
  1378. "This functions constructs the lexical environment for the text representation of
  1379. LISP objects --- without this, there could be no self refererence!"
  1380. (cond ((equal (%type-of object) 'instance)
  1381. `(let* ,(make-list-var-type-cells object)
  1382.         ,other-code))
  1383.       ((equal (%type-of object) 'structure)
  1384. `(let* ,(make-list-var-type-cells object)
  1385.         ,other-code))
  1386.       ((equal (%type-of object) 'hash-table)
  1387. `(let* ,(make-list-var-type-cells object)
  1388.           ,other-code))
  1389.       ((equal (%type-of object) 'circular-list)
  1390.        `(progn ,other-code))
  1391.       ((equal (%type-of object) 'vector)
  1392. `(let* ,(make-list-var-type-cells object) ,other-code))
  1393.       ((equal (%type-of object) 'array)
  1394. `(let* ,(make-list-var-type-cells object) ,other-code))
  1395.       ((cons-p object)
  1396. `(let* ,(make-list-var-type-cells object) ,other-code))
  1397.       ((simple-list-p object)`(progn ,other-code))
  1398.       ((quoted-list-p object)`(progn ,other-code))
  1399.       ((all-instance-list-p object)
  1400. `(let* ,(make-ilist-var-type-cells object)
  1401.             ,other-code))
  1402.       ((LISTP object)
  1403. `(let* ,(make-list-var-type-cells object) 
  1404.             ,other-code))
  1405. (T (warn "FROM MAKE LET FORM: object was of bogus type: ~A!!!"
  1406.      (%type-of object))
  1407.    (if other-code `(progn ,other-code)
  1408.        (progn (warn "there was no code to enclose!") nil)))))
  1409.  
  1410. #-(or lispm lucid allegro-v4.0 akcl)
  1411. (defun FILL-ARRAY (array l)
  1412. "Fill n-dimensional array with values from list."
  1413. (let ((list (flatten l)))
  1414. (if (= 1 (length (array-dimensions array)))
  1415.     (loop for count from 0 to (1- (length array)) do
  1416.       (setf (aref array count)(nth count list))
  1417.       finally (return-from fill-array array))
  1418. (progn (dotimes (i (array-total-size array) array)
  1419.        (setf (row-major-aref array i)(nth i list)))
  1420.     (return-from fill-array array)))))
  1421.  
  1422. #+(or allegro-v4.0 akcl)
  1423. (defun FILL-ARRAY (array l)
  1424. "Fill n-dimensional array with values from list."
  1425. (let ((list (flatten l)))
  1426. (dotimes (i (array-total-size array) array)
  1427.        (setf (row-major-aref array i)(nth i list)))
  1428.     (return-from fill-array array)))
  1429.  
  1430. #+lispm
  1431. (defun FILL-ARRAY (array l)
  1432. "Fill n-dimensional array with values from list."
  1433. (let ((list (flatten l))(array array))
  1434. (declare (sys:array-register array))
  1435. (if (= 1 (length (array-dimensions array)))
  1436.     (loop for count from 0 to (1- (length array)) do
  1437.       (setf (si:%1d-aref array count)(nth count list))
  1438.       finally (return-from fill-array array))
  1439. (progn  (dotimes (i (array-total-size array) array)
  1440.        (setf (row-major-aref array i)(nth i list)))
  1441.     (return-from fill-array array)))))
  1442.  
  1443. #-lucid
  1444. (defun MAPARRAY (function array)
  1445. "like mapcar, but maps a function over each element of an
  1446. n-dim array: the function to be applied is a function of two args,
  1447. the count and the element value at aref count in the array."
  1448. (let ((array array))
  1449. #+lispm (declare (sys:array-register-1d array))
  1450. (if (= 1 (length (array-dimensions array)))
  1451.     (dotimes (count (1- (length array)) array)
  1452. #+lispm(setf (sys:%1d-aref array count)(funcall function count (sys:%1d-aref array count)))
  1453. #-lispm(setf (aref array count)(funcall function count (aref array count)))
  1454. )
  1455. (progn  (dotimes (i (array-total-size array) array)
  1456.        (setf (row-major-aref array i)
  1457.          (funcall function i (aref array i))))
  1458.     (return-from maparray array)))))
  1459.  
  1460. (defun ARRAY-TYPE-T-P (X)
  1461. "Predicate, checks type and element-type of x."
  1462. (and (arrayp x)(not (stringp x))(equal (array-element-type x) T)))
  1463.  
  1464. (defun %TYPE-OF (x)
  1465. "Special type-of operator, returning a more intellignet type  for object caching:"
  1466. (cond ((%classp x) 'class)
  1467.       ((instance-p x) 'instance)
  1468.       ((structure-p x) 'structure)
  1469.       ((hash-table-p x) 'hash-table)
  1470.       ((typep x 'vector) 'vector)
  1471.       ((array-type-t-p x) 'array-type-t)
  1472.       ((arrayp x) 'array)
  1473.       ((cons-p x) 'cons)
  1474.       ((listp x)(if (circular-list-p x) 'circular-list 'list))
  1475.       (T (type-of x))))
  1476.  
  1477. (defun LOOKUP-OBJECT (X &key (mode :save))
  1478. "Accessor to the global object hashtable."
  1479. (rassoc x (gethash (%type-of x)(if (equal mode :save)
  1480.                  *save-object-hash-table*
  1481.                    *load-object-hash-table*))
  1482.  :test #'equalp))
  1483.  
  1484. (defun CACHE-OBJECT (x &key (mode :save))
  1485. "If the object is a structured object, cache the object in the object
  1486. hash table, if it isnt already there, along with its variable designation."
  1487. "If the object is a structured object, cache the object in the object
  1488. hash table, if it isnt already there, along with its variable designation."
  1489. (push (CONS (makevar) x) (gethash (%type-of x)
  1490. (if (equal mode :save) *save-object-hash-table*
  1491.   *load-object-hash-table*)))
  1492. x)
  1493.  
  1494. (defun LOOKUP-OBJECT-OR-CACHE (x)
  1495. ""
  1496. (cond ((null (lookup-object (eval x) :mode :load))
  1497.        (cache-object (eval x) :mode :load))
  1498.       (T x)))
  1499.  
  1500. (defun %%LIST-LENGTH (x)
  1501. ""
  1502. (cond ((cons-p x)(length x))
  1503.       ((listp x)(list-length x))
  1504.       (T NIL)))
  1505.  
  1506. (defun %LIST-LENGTH (x)
  1507. "Differs from ClTl2 LIST-LENGTH in that a multiple value return of
  1508. NIL and counter value are returned if its a circular list."
  1509.  (cond ((cons-p x)(length x))
  1510.       ((listp x)(do (( n 0 (+ n 2))
  1511.      (fast x (cddr fast))
  1512.      (slow x (cdr slow)))
  1513.      (nil)
  1514. (when (endp fast)(return (values n nil)))
  1515. (when (endp (cdr fast))(return (values (1+ n) nil)))
  1516. (when (and (eq fast slow)(> n 0))(return (values nil (/ n 2))))))
  1517. (T (values nil nil))))
  1518.  
  1519. (defun FIRSTN (n list)
  1520. "Return the first n elements of a list."
  1521. (let ((answers nil))
  1522. (dotimes (count (1- n) answers)
  1523.      (push (nth count list) answers))
  1524. (nreverse answers)))
  1525.  
  1526. (defun GET-CIRCULAR-LIST-ELEMENTS (circular-list)
  1527. "Given a circular list, get the repeating pattern."
  1528. (if (circular-list-p circular-list)
  1529.     (multiple-value-bind (status len) 
  1530.     (%list-length circular-list)
  1531.        status
  1532.       (firstn len circular-list))
  1533.     circular-list))
  1534.  
  1535. (defun MAKE-CIRCULAR-LIST (elts)
  1536. "Given non circular list elements elts, return a circular list of those elements."
  1537.  (rplacd (last elts) elts))
  1538.  
  1539. (defun CIRCULAR-LIST-DUMP-FORM (clist)
  1540. ""
  1541. (let ((ones (get-dump-form (get-circular-list-elements clist))))
  1542.   `(make-circular-list ,ones)))
  1543.  
  1544. (defun CIRCULAR-LIST-LENGTH (clist)
  1545. "Given a circular list, returns the number of non-circular elements before cycle:
  1546. returns an error if this is not a circular list!"
  1547. (multiple-value-bind (status length)
  1548. (%list-length clist)
  1549. (when status (error "this is not a circular list!"))
  1550. length))
  1551.  
  1552. (defun CIRCULAR-LIST-EQUAL (a b)
  1553. ""
  1554. (and (equal (circular-list-length a)(circular-list-length b))
  1555.      (equal (get-circular-list-elements a)(get-circular-list-elements b))))
  1556.  
  1557. (defun CIRCULAR-CONS-P (X)
  1558. (and (circular-list-p x)
  1559.      (eq (rest x) x)))
  1560.  
  1561. (defun CIRCULAR-CONS-DUMP-FORM (instance)
  1562. `(let ((first ,(get-dump-form (list (first instance)))))
  1563.   (setf (rest first) first)))
  1564.  
  1565. (defun CIRCULAR-LIST-P (X)
  1566. "Predicate to determine if something is a circular list, uses
  1567. LIST-LENGTH, which, unlike LENGTH, terminates and returns NIL if
  1568. the list is circular: LIST-LENGTH may not be in all versions of
  1569. LISP, as it is CLtL2: CHANGED TO INCLUDE THE RECURSIVE DEFINITION
  1570. OF CIRCULAR LISTS."
  1571. (if (not (listp x)) nil
  1572. (or (null (list-length x))(some #'circular-list-p x))))
  1573.  
  1574. (defun PCO-P (instance)
  1575. "A predicate to determine if a LISP object is a PCO."
  1576. (and (not (stringp instance))(member (%type-of instance) *pco-types*)))
  1577.  
  1578. (defun OBJECT-VAR (some-object &optional mode)
  1579. "The structure of the object htabs entries is (key . object),
  1580.  finding the cell with lookup-object, then the first element of the CONS!"
  1581. (if (null mode)(setf mode *mode-for-object-var*))
  1582. (let ((lo (lookup-object some-object :mode *mode-for-object-var*)))
  1583. (setf lo
  1584. (cond ((null lo)(warn "couldnt find ~a in object var!" some-object) NIL)
  1585.       ((listp lo)(first lo))
  1586.       (T lo)))))
  1587.  
  1588. (defun SET-OBJECT-VAR (object new-var)
  1589. "Given object and new var, and mode, set the appropriate hash table
  1590. key/value to the new-var."
  1591. (let* ((mode *mode-for-set-object-var*)
  1592. (there (lookup-object object :mode mode)))
  1593. (when (not there)(cache-object object :mode *mode-for-object-var*))
  1594. (rplaca (lookup-object object :mode *mode-for-object-var*)(object-var new-var))))
  1595.  
  1596. (defsetf object-var set-object-var)
  1597.  
  1598. (defun MAP-NONCIRCULAR-ELEMENTS-AND-COPY (function circ-list)
  1599. ""
  1600. (let ((elts (mapcar function
  1601.    (copy-list (get-circular-list-elements circ-list)))))
  1602. (make-circular-list elts)))
  1603.  
  1604. (defun MAP-OBJECT (function object)
  1605. "Generalized iterator for PCOs."
  1606. (cond ((circular-list-p object)
  1607.        (map-noncircular-elements-and-copy function object))
  1608.       ((vectorp object)
  1609.        #-(or akcl allegro-v4.0)
  1610.          (loop for count from 0 to (1- (length object)) do
  1611.          (setf (aref object count)
  1612.            (funcall function (aref object count)))
  1613.          finally (return object))
  1614.        #+(or akcl allegro-v4.0)
  1615.        (dotimes (count (1- (length object)) object)
  1616.        (setf (aref object count)(funcall function (aref object count))))
  1617.        )
  1618.       ((arrayp object)(maparray function object))
  1619.       ((structure-p object)(mapstruct function object))
  1620.       ((hash-table-p object)(maphash #'(lambda (key val)
  1621.                 (setf (gethash key object)
  1622.                   (funcall function val)))
  1623.                      object) object)
  1624.       ((instance-p object)(map-instance function object))
  1625.       (T (warn "Couldnt deal with object ~a, type: ~a.~%"
  1626.            object (type-of object)))))
  1627.  
  1628. ;;;  *** Beginning of CLOS eval-when... ***
  1629.  
  1630. #+clos 
  1631. (eval-when (load eval compile)
  1632.  
  1633. ;;; *** Dont-care vendor CLOS definitions. ***
  1634.  
  1635. (defun GET-CLASS-METACLASS (class-object)
  1636. "Given a class object, returns the metaclass name to help build
  1637.  CLASS-DUMP-FORM:  (NEW)."
  1638. (when (%classp class-object)
  1639. (let ((meta (%class-name (class-of (class-of class-object)))))
  1640. (if (not (equal meta 'clos::standard-class)) ;;; the default...
  1641. (list (list :metaclass meta))))))
  1642.  
  1643. (defun GET-CLASS-DOCUMENTATION (c)
  1644. ""
  1645. (or (documentation c) ""))
  1646.  
  1647. (defmethod INSTANCE-NAME ((instance T))
  1648.   "returns the symbol naming the given class object.
  1649.    NOTE: on the slimbolical hash-tables are FLAVORS.
  1650.    Therefore one must use HASH-TABLE-P instead of TYPE-OF,
  1651.    and the type returned is a Common Lisp entity, NOT a FLAVOR!"
  1652. (cond ((hash-table-p instance) 'hash-table)
  1653.       ((equal (%type-of instance) 'structure)(type-of instance))
  1654.       (T (clos::class-name (clos::class-of instance)))))
  1655.  
  1656. ;;; *** BEGINNING OF NON-MCL definitions! ***
  1657.  
  1658. #-(or akcl :mcl)
  1659. (eval-when (eval load compile)
  1660.  
  1661. (defun HAS-DUMP-FORM-P (class-name)
  1662.   "Predicate, returns t if a class has a user-defined DUMP FORM method."
  1663.   (get class-name 'user::%%DUMP-FORM-METHOD%%))
  1664.  
  1665. (defmacro DEFINE-DUMP-FORM (class-name arglist &body body)
  1666.   "Macro to define a user-defined dump-form for a given class-name.
  1667.    You could do this as two discrete steps, programmatically where you need it."
  1668.   `(progn (setf (get ',class-name 'user::%%dump-form-method%%) T)
  1669.       (defmethod DUMP-FORM ,arglist ,@body)
  1670.       ',class-name))
  1671.  
  1672. (defun GET-CLASS-DEFAULT-INITARGS (class)
  1673. "Gets the default-initargs out of the class object."
  1674. (mapcan #'(lambda (l)(list (first l)(get-dump-form (third l))))
  1675. (clos::class-direct-default-initargs class)))
  1676.  
  1677. (defmethod ALL-SLOTNAMES ((instance T) &optional (all-allocations T))
  1678.   "returns the names of the slots in instance, uses what MOP stuff is available."
  1679. (declare (ignore all-allocations))
  1680. (mapcar #'clos::slot-definition-name 
  1681.     (clos::class-DIRECT-slots (clos::class-of instance))))
  1682.                  ;;;;******
  1683.  
  1684. ) ;;; end of non-MCL definitions eval-when...
  1685.  
  1686. ;;; *** beginning of MCL common lisp definitions...***
  1687.  
  1688. #+:mcl
  1689. (eval-when (compile load eval)
  1690.  
  1691. (defun HAS-DUMP-FORM-P (class-name)
  1692.   "Predicate, returns t if a class has a user-defined DUMP FORM method."
  1693.   (get class-name '%%DUMP-FORM-METHOD%%))
  1694.  
  1695. (defmacro DEFINE-DUMP-FORM (class-name arglist &body body)
  1696.   "Macro to define a user-defined dump-form for a given class-name.
  1697.    You could do this as two discrete steps, programmatically where you need it."
  1698.   `(progn (setf (get ',class-name '%%dump-form-method%%) T)
  1699.       (defmethod DUMP-FORM ,arglist ,@body)
  1700.       ',class-name))
  1701.  
  1702. (defun CLASS-SLOTNAMES (class-object)
  1703. "Calls the clos internal function to compute class slot names."
  1704. (remove nil (mapcar #'first (class-slots class-object))))
  1705.  
  1706. (defun CLASS-SLOTS (class)
  1707. "MODIFIED: Given a class object, return all the slot objects."
  1708. #+supra (ccl::class-instance-slots class)
  1709. #+fx (ccl::class-slots class)
  1710. #+mcl2.0f3(class-direct-slots class)
  1711. )
  1712. ;;; ---- new experimental routines for MCL2.0f3 ------
  1713.  
  1714. #-mcl2.0f3
  1715. (defun CLASS-DIRECT-SLOTS (class)
  1716. "Given a class object return the slot objects."
  1717. (ccl::class-direct-slots class))
  1718.  
  1719. #+mcl2.0f3
  1720. (defun CLASS-DIRECT-SLOTS (class)
  1721. "Given a class object return the slot objects."
  1722. (ccl::class-direct-class-slots class))
  1723.  
  1724. (defun GET-DEFSTRUCT-CONSTRUCTOR (name)
  1725. "default definition for now...."
  1726. (read-from-string (concatenate 'string "make-" (format nil "~a" name))))
  1727.  
  1728. (defun INSTANCE-P (X)
  1729. "Predicate to determine whether something is an INSTANCE."
  1730. (and (not (%classp x))(typep x 'standard-object)))
  1731.  
  1732. (defun STRUCTURE-P (X)
  1733. "Predicate to determine whether something is a structure INSTANCE."
  1734. (ccl:structurep x))
  1735.  
  1736. (defun GET-CLASS-DEFAULT-INITARGS (class)
  1737. "Gets the default-initargs out of the class object."
  1738. class
  1739. nil)
  1740.  
  1741. (defun %CLASSP (X)
  1742. "predicate to tell if something is a class object."
  1743. (typep x 'ccl::standard-class))
  1744.  
  1745. (defun %GENERIC-FUNCTION-DOCUMENTATION (f)
  1746. ""
  1747. (or (documentation f) ""))
  1748.  
  1749. (defun GET-SLOT-TYPE (S)
  1750. ""
  1751. (first (reverse s)))
  1752.  
  1753. (defun GET-DIRECT-SLOTS (class-object)
  1754. "Gets the immediately available 'new' non inheried slot OBJECTS."
  1755. (class-direct-slots class-object))
  1756.  
  1757. (defun GET-SLOT-DOCUMENTATION (s)
  1758. ""
  1759. (or (documentation s) ""))
  1760.  
  1761. (defun GET-SLOT-NAME (S)
  1762. "Method to get the name from a standard slot."
  1763. (clos::slot-definition-name s))
  1764.  
  1765. (defun SLOT-HAS-AN-INITFORM-P (slot-object)
  1766. ""
  1767. (second slot-object))
  1768.  
  1769. (defun GET-SLOT-READERS (s)
  1770. ""
  1771. s
  1772. nil)
  1773.  
  1774. (defun GET-SLOT-WRITERS (s)
  1775. ""
  1776. s
  1777. nil)
  1778.  
  1779. (defun %SLOT-DEFINITION-ALLOCATION (S)
  1780. ""
  1781. s
  1782. NIL)
  1783.  
  1784. (defun GET-SLOT-NAMED (instance name)
  1785. ""
  1786. (find-if #'(lambda (slot)
  1787. (equal (get-slot-name slot) name))
  1788.      (all-slots instance)))
  1789.  
  1790. (defun GET-SLOT-ALLOCATION (S)
  1791. "Method to get the type of allocation from a standard slot: oneof :CLASS or :INSTANCE."
  1792. (let ((alloc (%slot-definition-allocation s)))
  1793. (cond ((%classp alloc) :CLASS)
  1794.       ((member alloc '(:INSTANCE :CLASS)) alloc) 
  1795.       (T :INSTANCE))))
  1796.  
  1797. (defmethod GET-SLOT-INITFORM (s)
  1798. ""
  1799. (when (slot-has-an-initform-p s)
  1800. (first (second s))))
  1801.  
  1802. (defun %GET-SLOT-INITFORM (S)
  1803. "Method to create the iniform pair, if there is an initform value!"
  1804. (if  *save-contents-of-class-allocated-classes*
  1805. (when (and (equal (get-slot-allocation s) :CLASS)
  1806.        (slot-has-an-initform-p s))        
  1807. (list :initform (get-dump-form (funcall (get-slot-reader s) s)))))
  1808. (when (slot-has-an-initform-p s)
  1809. (list :initform  (get-slot-initform s))))
  1810.  
  1811. (defun GET-SLOT-INITARGS (s)
  1812. ""
  1813. (ccl::class-slot-initargs s))
  1814.  
  1815. (defun GET-SLOT-INITARG (s)
  1816. ""
  1817. (first (ccl::class-slot-initargs s)))
  1818.  
  1819. (defmethod ALL-SLOTNAMES ((instance T) &optional (all-allocations T))
  1820.   "returns the names of the slots in instance, uses what MOP stuff is available."
  1821. (declare (ignore all-allocations))
  1822. (REMOVE NIL (mapcar #'clos::slot-definition-name 
  1823.                 (class-slots (clos::class-of instance)))))
  1824.  
  1825. (defun ALL-SLOTS (instance)
  1826. "Gets all the slots from the instances class, whether inherited or not."
  1827. (class-slots (clos::class-of instance)))
  1828.  
  1829. (defun %CLASS-NAME (x)
  1830. "If instance, gets the name of the class of the instance."
  1831. (if (instance-p x)(clos::class-name (clos::class-of x))
  1832. (clos::class-name x)))
  1833.  
  1834. (defun GET-SUPERCLASS-NAMES (class)
  1835. ""
  1836. (mapcar #'clos::class-name (clos::class-direct-superclasses class)))
  1837.  
  1838. ) ;;; *END OF MCL CCL CLOS eval-when! ****
  1839.  
  1840. ;;; *** Non-LISP machine CLOS eval-when. ***
  1841.  
  1842. #-(or lispm :mcl akcl)
  1843. (eval-when (load compile eval)
  1844.  
  1845. (defun %GENERIC-FUNCTION-DOCUMENTATION (f)
  1846. ""
  1847. (or (documentation f) ""))
  1848.  
  1849. (defun GET-SLOT-TYPE (S)
  1850. "Method to get the type from a standard slot:
  1851.  this works for most things EXCEPT Genera 8x CLOS."
  1852. (clos::slotd-type s))
  1853.  
  1854. ;;;;(defun GET-DIRECT-SLOTS (class-object)
  1855. ;;;""
  1856. ;;;(clos::class-class-direct-slots class-object))
  1857.  
  1858. (defun %GENERIC-FUNCTION-P (x)
  1859. "Predicate, returns t for generic functions. causes symbol conflict problem
  1860.  in genera 8.0."
  1861. (clos::generic-function-p x))
  1862.  
  1863. )
  1864.  
  1865. ;;; *** END OF NON LISPM EVAL-WHEN ***
  1866.  
  1867. ;;; *** Lisp Machine Genera 8.x CLOS eval-when. ***
  1868.  
  1869. #+lispm
  1870. (eval-when (load eval compile)
  1871.  
  1872. (defun %GENERIC-FUNCTION-P (x)
  1873. "Predicate, returns t for generic functions. causes symbol conflict problem
  1874.  in genera 8.0."
  1875. (clos-internals::generic-function-p x))
  1876.  
  1877. (defun BUILTIN-CLASS-P (class-object)
  1878. "Predicate to determine whether a class object (that which is returned by (FIND-CLASS <NAME>))
  1879.  is a BUILTIN class or not."
  1880. (typep class-object 'clos:built-in-class))
  1881.  
  1882. (defmethod CLASS-NAME ((object t))
  1883. "We use this in %classp. we already know its either an instance or a class.
  1884.  if its an instance, it has no name. CLASS-NAME on standard class takes care of real
  1885.  class objects."
  1886. nil)
  1887.  
  1888. (defun %CLASSP (X)
  1889. "The function CLASSP is not defined at all in Genera."
  1890. (and (instance-p x)(find-class (class-name x) nil)))
  1891.  
  1892. (defun %GENERIC-FUNCTION-DOCUMENTATION (f)
  1893. ""
  1894. (or (documentation f) ""))
  1895.  
  1896. (defun INSTANCE-P (x)
  1897. "This will work in Genera 8x CLOSes: filters out entities that are flavor instances.
  1898.  Also filters out things that are defstruct instances."
  1899. (and (sys:instancep x)(not (flavor:find-flavor (type-of x) nil))))
  1900.  
  1901. (defun GET-SLOT-TYPE (S)
  1902. "This will work for Genera 8x CLOSses."
  1903. (clos:slot-definition-type s))
  1904.  
  1905. (defun GET-DIRECT-SLOTS (class-object)
  1906. ""
  1907. (clos:class-direct-slots class-object))
  1908.  
  1909. (defun GET-SLOT-DOCUMENTATION (s)
  1910. ""
  1911. (or (documentation s) ""))
  1912.  
  1913. (defun GET-SLOT-NAME (S)
  1914. "Method to get the name from a standard slot."
  1915. (clos::slot-definition-name s))
  1916.  
  1917. (defun SLOT-HAS-AN-INITFORM-P (slot-object)
  1918.   (clos::slot-definition-initform slot-object))
  1919.  
  1920. (defun GET-SLOT-READERS (slot-object)
  1921.   (clos::slot-definition-readers slot-object))
  1922.  
  1923. (defun GET-SLOT-WRITERS (slot-object)
  1924.   (clos::slot-definition-writers slot-object))
  1925.  
  1926. (defun GET-SLOT-NAMED (instance name)
  1927. (find-if #'(lambda (slot)(equal (get-slot-name slot) name))
  1928.      (all-slots instance)))
  1929.  
  1930. (defun GET-SLOT-ALLOCATION (S)
  1931. "Method to get the type of allocation from a standard slot: oneof :CLASS or :INSTANCE."
  1932. (let ((alloc (clos::slot-definition-allocation s)))
  1933. (cond ((%classp alloc) :CLASS)
  1934.       ((member alloc '(:INSTANCE :CLASS)) alloc) 
  1935.       (T :INSTANCE))))
  1936.  
  1937. (defmethod GET-SLOT-INITFORM (s)
  1938. ""
  1939. (when (slot-has-an-initform-p s)(clos::slot-definition-initform s)))
  1940.  
  1941. (defun %GET-SLOT-INITFORM (S)
  1942. "Method to create the iniform pair, if there is an initform value!"
  1943. (if  *save-contents-of-class-allocated-classes*
  1944. (when (and (equal (get-slot-allocation s) :CLASS)
  1945.        (slot-has-an-initform-p s))        
  1946. (list :initform (get-dump-form (funcall (get-slot-reader s) s)))))
  1947. (when (slot-has-an-initform-p s)
  1948. (list :initform  (clos::slot-definition-initform s))))
  1949.  
  1950. (defun GET-SLOT-INITARGS (s)
  1951. (clos::slot-definition-initargs s))
  1952.  
  1953. (defun GET-SLOT-INITARG (s)
  1954. (first (clos::slot-definition-initargs s)))
  1955.  
  1956. ) ;;; end of Genera 8x CLOS eval-when.
  1957.  
  1958. ;;; Lucid CLOS eval when...
  1959.  
  1960. #+lucid
  1961. (eval-when (load eval compile)
  1962.  
  1963. (defun MAPARRAY (function array)
  1964. "like mapcar, but maps a function over each element of an
  1965. n-dim array: the function to be applied is a function of two args,
  1966. the count and the element value at aref count in the array."
  1967. (let* ((vec (sys:underlying-simple-vector array))
  1968.       (len (1- (length vec))))
  1969. (loop for count from 0 to len do (setf (aref vec count)
  1970.   (funcall function count (aref vec count)))
  1971.   finally (return array))))                 
  1972.  
  1973. (defun FILL-ARRAY (array l)
  1974. "Fill n-dimensional array with values from list."
  1975. (let* ((vec (sys:underlying-simple-vector array))
  1976.        (len (1- (length vec)))
  1977.        (data (flatten l)))
  1978. (loop for index from 0 to len 
  1979. do (setf (aref vec index)(nth index data))
  1980.   finally (return array))))                 
  1981.  
  1982. (defun GET-SUPERCLASS-NAMES (class)
  1983. "Expects the object returned by FIND-CLASS."
  1984. (mapcar #'clos::class-name (clos::class-direct-superclasses class)))
  1985.  
  1986. (defun INSTANCE-P (x)
  1987. "Alternate def as a function for lucid 4.0."
  1988. (and (system:standard-object-p x)(not (system:classp x))))
  1989.  
  1990. (defun GET-SLOT-DOCUMENTATION (s)
  1991. ""
  1992. (or (clos::slotd-documentation s) ""))
  1993.  
  1994. (defun GET-SLOT-NAME (S)
  1995. "Method to get the name from a standard slot."
  1996. (clos::slotd-name s))
  1997.  
  1998. (defun GET-SLOT-READERS (slot-object)
  1999.   (clos::slotd-readers slot-object))
  2000.  
  2001. (defun GET-SLOT-WRITERS (slot-object)
  2002.   (clos::slotd-writers slot-object))
  2003.  
  2004. (defun GET-SLOT-ALLOCATION (S)
  2005. "Method to get the type of allocation from a standard slot: oneof :CLASS or :INSTANCE."
  2006. (let ((alloc (clos::slotd-allocation s)))
  2007. (cond ((%classp alloc) :CLASS)
  2008.       ((member alloc '(:INSTANCE :CLASS)) alloc) 
  2009.       (T :INSTANCE))))
  2010.  
  2011. (defun %CLASSP (X)
  2012. "CLASSP is not exported in Lucid or EXCL, and is not defined at all in Genera!"
  2013. (clos::classp x))
  2014.  
  2015. (defmethod GET-SLOT-INITFORM (s)
  2016. ""
  2017. (when (slot-boundp s 'clos::initform)
  2018.        (clos::slotd-initform s)))
  2019.  
  2020. (defun %GET-SLOT-INITFORM (S)
  2021. "Method to create the iniform pair, if there is an initform value!"
  2022. (if  *save-contents-of-class-allocated-classes*
  2023. (when (and (equal (get-slot-allocation s) :CLASS)
  2024.        (slot-boundp s 'clos::initform))
  2025. (list :initform (get-dump-form (funcall (get-slot-reader s) s))))
  2026. (when (slot-boundp s 'clos::initform)
  2027.       (list :initform  (clos::slotd-initform s)))))
  2028.  
  2029. (defun GET-SLOT-INITARGS (s)
  2030. (clos::slotd-initargs s))
  2031.  
  2032. (defun GET-SLOT-INITARG (s)
  2033. (first (clos::slotd-initargs s)))
  2034.  
  2035. (defun BUILTIN-CLASS-P (X)
  2036.   "Predicate to determine whether a class object is a builtin class. returns
  2037.    T if it is."
  2038.   (and (%classp x)(member (%class-name x)
  2039.   (mapcar #'first clos-system::built-in-classes) :test #'equal)))
  2040.  
  2041. ) ;;; *** end of Lucid CLOS eval-when. ***
  2042.  
  2043. ;;; *** Allegro non-MCL eval-when (e.g. on Suns.) ***
  2044.  
  2045. #+excl
  2046. (eval-when (load eval compile)
  2047.  
  2048. (defun GET-SLOT-DOCUMENTATION (s)
  2049. ""
  2050. (or (documentation s) ""))
  2051.  
  2052. (defun GET-SLOT-READERS (slot-object)
  2053.   (clos::slotd-readers slot-object))
  2054.  
  2055. (defun GET-SLOT-WRITERS (slot-object)
  2056.   (clos::slotd-writers slot-object))
  2057.  
  2058. (defun GET-SLOT-ALLOCATION (S)
  2059. "Method to get the type of allocation from a standard slot: oneof :CLASS or :INSTANCE."
  2060. (let ((alloc (clos::slotd-allocation s)))
  2061. (cond ((%classp alloc) :CLASS)
  2062.       ((member alloc '(:INSTANCE :CLASS)) alloc) 
  2063.       (T :INSTANCE))))
  2064.  
  2065. (defun GET-SLOT-NAME (S)
  2066. "Method to get the name from a standard slot."
  2067. (clos::slotd-name s))
  2068.  
  2069. (defun %CLASSP (X)
  2070. ""
  2071. (or (typep x 'clos::standard-class)(typep x 'clos::built-in-class)))
  2072.  
  2073. (defmethod GET-SLOT-INITFORM (s)
  2074. ""
  2075. (when (slot-boundp s 'clos::initform)
  2076.        (clos::slotd-initform s)))
  2077.  
  2078. (defun %GET-SLOT-INITFORM (S)
  2079. "Method to create the iniform pair, if there is an initform value!"
  2080. (if  *save-contents-of-class-allocated-classes*
  2081. (when (and (equal (get-slot-allocation s) :CLASS)
  2082.        (slot-boundp s 'clos::initform))
  2083. (list :initform (get-dump-form (funcall (get-slot-reader s) s))))
  2084. (when (slot-boundp s 'clos::initform)
  2085.       (list :initform  (clos::slotd-initform s)))))
  2086.  
  2087. (defun GET-SLOT-INITARGS (s)
  2088. (clos::slotd-initargs s))
  2089.  
  2090. (defun GET-SLOT-INITARG (s)
  2091. (first (clos::slotd-initargs s)))
  2092.  
  2093. (defun BUILTIN-CLASS-P (X)
  2094.   "Predicate to determine whether a class object is a builtin class. returns
  2095.    T if it is."
  2096. (and (%classp x)(typep x 'clos::built-in-class)))
  2097.  
  2098. #+allegro-v4.1
  2099. (defun INSTANCE-P (X)
  2100. "With the 4.0 series, structures are instances as well: exclude these."
  2101. (and (not (typep x 'clos::structure-class))
  2102.  (not (%classp x))(excl::standard-instance-p x)))
  2103.  
  2104. #+allegro-v4.0
  2105. (defun INSTANCE-P (X)
  2106. "With the 4.0 series, structures are instances as well: exclude these:
  2107.  NOTE, removed the clause testing for clos:structure-object."
  2108.  (not (%classp x))(excl::standard-instance-p x))
  2109.  
  2110. ) ;;; *** end of non-MCL Allegro (like Sun Allegro) CLOS eval-when. ***
  2111.  
  2112. ) ;;; *** END OF CLOS EVAL WHEN *******
  2113.  
  2114. ;;; PCL Dependent functions & methods,,,
  2115.  
  2116. #+pcl
  2117. (eval-when (load eval compile)
  2118.  
  2119. (defun INSTANCE-NAME (instance)
  2120.   "returns the symbol naming the given class object."
  2121.   (pcl::class-name (pcl::class-of instance)))
  2122.  
  2123. (defun ALL-SLOTNAMES (instance &optional (all-allocations T))
  2124.   "returns the names of the slots in instance."
  2125. (let ((them (mapcar #'(lambda (slot)
  2126.             (pcl::slot-value slot 'pcl::name))
  2127.           (pcl::slots-to-inspect (pcl::class-of instance)
  2128.                  instance))))
  2129. (if all-allocations them 
  2130.       (remove-if-not #'(lambda (slot)
  2131.           (equal (pcl::slotd-allocation slot) :instance))
  2132.                   them))))
  2133.  
  2134. (defun ALL-SLOTS (instance &optional (all-allocations T))
  2135.   "returns the names of the slots in instance."
  2136. (let ((them (pcl::slots-to-inspect (pcl::class-of instance)
  2137.                  instance)))
  2138. (if all-allocations them 
  2139.       (remove-if-not #'(lambda (slot)
  2140.           (equal (pcl::slotd-allocation slot) :instance))
  2141.                   them))))
  2142.  
  2143. ) ;;; *** END PCL EVAL-WHEN.... ***
  2144.  
  2145. ;;; Independent.
  2146.  
  2147. (defun GET-CLASS-SUPERCLASSES (class)
  2148. "Returns a list of the NAMES (symbol list) of the direct superclasses of the class object."
  2149. (let ((the-ones (get-superclass-names class)))
  2150.   (if *supress-standard-object* (delete 'standard-object the-ones)
  2151.     the-ones)))
  2152.  
  2153. (defun GET-SLOT-READER (slot-object)
  2154.   (first (get-slot-readers slot-object)))
  2155.  
  2156. (defun GET-SLOT-WRITER (slot-object)
  2157.   (first (get-slot-writers slot-object)))
  2158.  
  2159. (defun ACCESSOR-EXISTS-P (S)
  2160. "Predicate: Returns T iff the slot has both a reader and a standard writer."
  2161. (let* ((readers (get-slot-readers s))
  2162.        (writers (get-slot-writers s))
  2163.        (accessors (some #'(lambda (writer)
  2164.                 (and (listp writer)
  2165.                  (equal (first writer) 'SETF)
  2166.                  (second writer)
  2167.                  (member (second writer) readers
  2168.                      :test #'equal)))
  2169.             writers)))
  2170.   accessors))
  2171.  
  2172. (defun GET-SLOT-ACCESSOR (s)
  2173. "Returns the first slot accessor alone."
  2174. (let ((val  (first (get-slot-readers s))))
  2175. (when (and val (accessor-exists-p s))
  2176.       val)))
  2177.  
  2178. (defun %GET-SLOT-NAME (S)
  2179. "Method to get the name from a standard slot."
  2180. (get-slot-name s))
  2181.  
  2182. (defun %GET-SLOT-ALLOCATION (S)
  2183. "Method to get the type of allocation from a standard slot: oneof :CLASS or :INSTANCE."
  2184. (let ((val  (get-slot-allocation s)))
  2185. (when val (list :allocation val))))
  2186.  
  2187. (defun %GET-SLOT-TYPE (S)
  2188. "Method to get the type from a standard slot.."
  2189. (list :type (get-slot-type s)))
  2190.  
  2191. (defun %GET-SLOT-INITARG (S)
  2192. "Method to get the first initarg found for the standard slot instance supplied."
  2193. (let ((val (or (first (get-slot-initargs s))
  2194. (if *use-default-class-initargs* (make-keyword (get-slot-name s))))))
  2195. (when val (list :initarg val))))
  2196.  
  2197. (defun %GET-SLOT-READER (slot)
  2198. "Method to determine whether to use an accessor or a reader. Does not splice
  2199.  into the dump form if there is no reader defined."
  2200. (when (null (%get-slot-accessor slot))
  2201.   (let ((val  (GET-SLOT-reader slot)))
  2202.     (when val (list :reader val)))))
  2203.  
  2204. (defun %GET-SLOT-WRITER (slot)
  2205. "Method to determine whether to use an accessor or a writer. Does not splice
  2206.  into the dump form if there is no writer defined."
  2207. (when (null (%get-slot-accessor slot))
  2208.   (let ((val (GET-SLOT-WRITER slot)))
  2209.       (when val (list :writer val)))))
  2210.  
  2211. (defun %GET-SLOT-DOCUMENTATION (S)
  2212. ""
  2213. (list :documentation (or (GET-SLOT-DOCUMENTATION s) "")))
  2214.  
  2215. (defun %GET-SLOT-ACCESSOR (S)
  2216. ""
  2217. (let ((val  (GET-SLOT-READER s)))
  2218. (when (and val (accessor-exists-p s))
  2219.       (list :accessor val))))
  2220.  
  2221. (defmethod METHODP ((thing null))
  2222. "NIL is not a method."
  2223. nil)
  2224.  
  2225. (defmethod METHODP ((thing t)) 
  2226. "Anything else is not a method."
  2227.   nil)
  2228.  
  2229. (defmethod MBOUNDP ((name symbol))
  2230.   "Predicate: returns t if this name is a method as opposed to a function/macro."
  2231.   (when (methodp name) T))
  2232.  
  2233. (defmethod MBOUNDP ((name null))
  2234. "vacuous case for NIL."
  2235. NIL)
  2236.  
  2237. (defmethod MBOUNDP ((name t))
  2238.   "Predicate: returns t if this name is a method as opposed to a function/macro."
  2239.   (when (methodp name) T))
  2240.  
  2241. (defun SLOT-DATA-AS-PLIST (slot)
  2242. "Generates the slot value pairs of the slot descriptor as a property list, 
  2243.  of course the name is stuck on the front."
  2244. (let ((name (get-slot-name slot))
  2245.       (initarg (get-slot-initarg slot))
  2246.       (accessor (get-slot-accessor slot))
  2247.       (initform (get-slot-initform slot))
  2248.       (type (get-slot-type slot))
  2249.       (documentation (get-slot-documentation slot))
  2250.       (allocation (get-slot-allocation slot)))
  2251. (if accessor
  2252. (list name :initarg initarg 
  2253.       :accessor accessor
  2254.       :initform initform
  2255.       :type type
  2256.       :documentation documentation
  2257.       :allocation allocation)
  2258. (list name :initarg initarg 
  2259.       :initform initform
  2260.       :type type
  2261.       :documentation documentation
  2262.       :allocation allocation))))
  2263.  
  2264. (defun CONSTRUCT-SLOT-SPEC (slot)
  2265. "The internal dump-form constructor for slots."
  2266. (let ((name (%get-slot-name slot))
  2267.       (initarg-pair (%get-slot-initarg slot))
  2268.       (type-pair (%get-slot-type slot))
  2269.       (accessor-pair (%get-slot-accessor slot))
  2270.       (reader-pair (%get-slot-reader slot))
  2271.       (writer-pair (%get-slot-writer slot))
  2272.       (allocation-pair (%get-slot-allocation slot))
  2273.       (initform-pair (%get-slot-initform slot))
  2274.       (documentation-pair (%get-slot-documentation slot)))
  2275.   `(,name ,@initarg-pair
  2276.     ,@type-pair
  2277.     ,@accessor-pair
  2278.     ,@reader-pair
  2279.     ,@writer-pair
  2280.     ,@allocation-pair
  2281.     ,@initform-pair
  2282.     ,@documentation-pair)))
  2283.  
  2284. (defun GENERATE-CLASS-SLOT-FORM (slotd)
  2285. "Default method for rev4b --- seems to be defective...
  2286.  This one gets called by CLASS-DUMP-FORM."
  2287. (construct-slot-spec slotd))
  2288.  
  2289. (defun SORT-ALLOCATED-SLOTS (class-object)
  2290. ""
  2291. (let ((slots (class-slots class-object)))
  2292. (values
  2293. (remove-if-not #'(lambda (slot)(equal (get-slot-allocation slot)
  2294.                       :CLASS))
  2295.            slots)
  2296. (remove-if-not #'(lambda (slot)(equal (get-slot-allocation slot)
  2297.                       :INSTANCE))
  2298.            slots))))
  2299.  
  2300. ;;;; Only allow class save, method save, and generic function save when this
  2301. ;;; file is loaded: control this with :class-save on the features list.
  2302. ;;; end of lucid eval-when.
  2303.  
  2304. ;;; NOTE! Returned result from CLASS-DIRECT-SLOTS varies with the vendor!
  2305.  
  2306. #-(or :mcl lucid lispm akcl)
  2307. (defun CLASS-SLOTS (class-object)
  2308. "Calls the clos internal function to compute class slot objects."
  2309. (clos::class-direct-slots class-object))
  2310.  
  2311. ;;; CLOS/PCL independent class accessor methods.
  2312.  
  2313. (eval-when (load eval compile)
  2314.  
  2315. (defun DO-SPECIALIZER (spec)
  2316. "Map objects to class names."
  2317. (cond ((SYMBOLP SPEC) spec)
  2318.       ((%CLASSP SPEC)`(FIND-CLASS ',(%class-name spec)))
  2319.       (T SPEC)))
  2320.  
  2321.  
  2322.  
  2323. #-(or allegro-v4.0 akcl)
  2324. (defun DO-SPECIALIZERS (lst)
  2325. (loop for spec in lst collect (do-specializer spec)))
  2326.  
  2327. #+(or allegro-v4.0 akcl)
  2328. (defun DO-SPECIALIZERS (lst)
  2329. (let ((answers nil))
  2330. (dolist (spec lst answers)
  2331.     (setf answers (append (list (do-specializer spec)))))
  2332. answers))
  2333.  
  2334. (defun FIND-GENERIC-FUNCTION (name)
  2335. "A function given the name of a supposed generic function,
  2336.  returns the function object if it exists, NIL otherwise."
  2337. (cond ((and (fboundp name)(%generic-function-p name))
  2338.        (symbol-function name))
  2339.       (T NIL)))
  2340.  
  2341.  
  2342.  
  2343. (defun GENERATE-CLASS-OPTIONS-FORM (class)
  2344. "Generates a dump form for the default-initargs, metaclass,
  2345.  documentation components of a class object...."
  2346. (let ((default-initargs (get-class-default-initargs class))
  2347.       (metaclass (get-class-metaclass class)))
  2348.   (if default-initargs
  2349.       `((:default-initargs ,@default-initargs)
  2350.     ,@metaclass
  2351.     (:documentation ,(or (get-class-documentation class) "")))
  2352.     `(,@metaclass
  2353.       (:documentation ,(or (get-class-documentation class) ""))))))
  2354.  
  2355. #+(or akcl allegro-v4.0)
  2356. (defun GENERATE-CLASS-SLOT-FORMS (class)
  2357. "This generates dump forms for all the slots in the class object."
  2358. (let ((slots nil))
  2359. (dolist (slot (class-slots class) slots)
  2360.       (setf slots (append slots 
  2361.       (list (generate-class-slot-form slot)))))
  2362. slots))
  2363.  
  2364. #-(or akcl allegro-v4.0)
  2365. (defun GENERATE-CLASS-SLOT-FORMS (class)
  2366. "This generates dump forms for all the slots in the class object."
  2367. (loop for slot in (class-slots class)
  2368.       collect (generate-class-slot-form slot)))
  2369.  
  2370. ) ;;; end of class-save eval-when.
  2371.  
  2372.  
  2373. ;;; Now, the Symbolics....
  2374.  
  2375. #+lispm
  2376. (defun HASH-TABLE-SIZE (x)
  2377. (scl:send x :size))
  2378.  
  2379. #+lispm
  2380. (defun HASH-TABLE-TEST (x)
  2381. (si:function-name (cli::test-function x)))
  2382.  
  2383. (defun PSEUDO-QUOTE-READER (stream subchar arg)
  2384.   "Reader to convert a function spec into a more parsable format."
  2385.   (declare (ignore subchar arg))
  2386.   (eval
  2387.    (list 'quote
  2388.      (second (read-from-string 
  2389.           (nsubstitute #\space #\#
  2390.        (concatenate 'string "(" 
  2391.         (read-line stream t nil t) ")")
  2392.                    :test #'equal))))))
  2393.  
  2394. (defun MAKE-KEYWORD (x)
  2395. "Makes a keyword out of a symbol."
  2396.  (if (keywordp x) x (intern (symbol-name x) 'keyword)))
  2397.  
  2398. (defun NEWSYM (symbol)
  2399.   "Similar to GENSYM, but allows access to the gensym counter unlike pre-ANSI GENSYM."
  2400.   (if (null (get symbol 'namecounter))
  2401.       (setf (get symbol 'namecounter) 0))
  2402.   (read-from-string (concatenate 'string (string symbol)
  2403.   (format nil "~S" (incf (get symbol 'namecounter))))))
  2404.  
  2405. (defmethod COPY-INSTANCE ((instance T))
  2406.   "Provides shallow copying of any instance: returns a new copy of a 
  2407. given clos instance, writ as a method so youse gys can write ur own."
  2408. (let* ((copy (make-instance (instance-name instance)))
  2409.        (slots (all-slotnames instance)))
  2410.     (dolist (slot slots)
  2411.       (if (not (slot-boundp instance slot))
  2412.       (slot-makunbound copy slot)
  2413.       (setf (slot-value copy slot)(slot-value instance slot))))
  2414.     copy))
  2415.  
  2416. ;;; ---- unbound slot handler ----
  2417.  
  2418. (defun UNBOUND-SLOT-TOKEN-P (x)
  2419. "Predicate: "
  2420. (and (symbolp x)(equal x *unbound-slot-token*)))
  2421.  
  2422. #+(or akcl allegro-v4.0)
  2423. (defmethod ALL-SLOTS-AND-VALUES ((instance T))
  2424. "returns an alist of slot value pairs.
  2425.  NOTE: Each alist cell is a LIST, NOT a CONS!
  2426.  Also, this has been modified to deal with unbound slots."
  2427. (let ((answers nil))
  2428.   (dolist (slot (all-slotnames instance) answers)
  2429.   (setf answers (nconc answers
  2430.     (list slot (if (slot-boundp instance slot)
  2431.              (slot-value instance slot)
  2432.                  *unbound-slot-token*)))))
  2433.   answers))
  2434.  
  2435. #-(or akcl allegro-v4.0)
  2436. (defmethod ALL-SLOTS-AND-VALUES ((instance T))
  2437. "returns an alist of slot value pairs.
  2438.  NOTE: Each alist cell is a LIST, NOT a CONS!
  2439.  Also, this has been modified to deal with unbound slots."
  2440.   (loop for slot in (all-slotnames instance) nconc
  2441.     (list slot (if (slot-boundp instance slot)
  2442.              (slot-value instance slot)
  2443.                  *unbound-slot-token*)) into answers
  2444.              finally (return answers)))
  2445.  
  2446. (defun PRSLOT (key val &optional (stream *standard-output*))
  2447. "Simple function to be used by MAP-INSTANCE, printing out a slots key and value, ala
  2448. DESCRIBE."
  2449. (format stream "Key: ~a, Value: ~a~%" key val))
  2450.  
  2451. #+allegro-v4.0
  2452. (defun MAP-INSTANCE (function instance &key (modify T)(concat nil))
  2453. "Iterator over the slots in an instance, ala MAPHASH. Takes a function of the
  2454. keyword/ value (2 arguments, not ONE!)."
  2455. (let* ((slotnames (all-slotnames instance))
  2456.        (answers nil)
  2457.        (result nil))
  2458. (dolist (slot slotnames answers)
  2459.     (setf result (funcall function slot (slot-value instance slot)))
  2460.     (when concat (setf answers (append answers (list result))))
  2461.     (when modify (setf (slot-value instance slot) result)))
  2462.         (if (null concat) instance (flatten1 answers))))
  2463.  
  2464. #-(or akcl allegro-v4.0)
  2465. (defun MAP-INSTANCE (function instance &key (modify T)(concat nil))
  2466. "Iterator over the slots in an instance, ala MAPHASH. Takes a function of the
  2467. keyword/ value (2 arguments, not ONE!)."
  2468. (let* ((init (all-slots-and-values instance))
  2469.       (answer (loop with con = nil
  2470.       until (null init)
  2471.       as key = (pop init)
  2472.       as val = (pop init)
  2473.       as result = (funcall function key val)
  2474.       when concat do (setf con (append con (list result)))
  2475.       when modify do (setf (slot-value instance key) result)
  2476.       finally (return (if (null concat) instance (flatten1 con))))))
  2477.   answer))
  2478.  
  2479. (defun CLEAR-GLOBAL-VARS-AND-HTABS ()
  2480. "Initializes the SAVE-OBJECT enviroment for recording graph cycles."
  2481.      (setf *structs-seen* nil *struct-vars* nil)
  2482.      (setf *vectors-seen* nil *vector-vars* nil)
  2483.      (setf *arrays-seen* nil *array-vars* nil)
  2484.      (setf *htabs-seen* nil *htab-vars* nil)
  2485.      (setf *seen* nil *vars* nil)
  2486.          (clrhash *save-object-hash-table*))
  2487.  
  2488. (defun CLEAR-SAVE-OBJECT ()
  2489. "shorthand to clear the environment."
  2490. (clear-global-vars-and-htabs)
  2491. )
  2492.  
  2493. ;;; The main routine, SAVE-OBJECT.
  2494.  
  2495. (defun SAVE-OBJECT (object-instance filename &key
  2496.                     (compile nil)
  2497.                     (variable '*db-input*)
  2498.                     (if-exists :append)
  2499.                     (print-pretty nil)
  2500.                     (max-print-level 10000000)
  2501.                     (package nil) 
  2502.                     (if-does-not-exist :create))
  2503.          (setf *global-instance-count* 0)
  2504.      (setf *global-object-count* 0)
  2505.      (clear-global-vars-and-htabs)
  2506. (let* ((*print-level*  max-print-level)
  2507.        (*print-circle* t)
  2508.        #+lispm (scl::*print-structure-contents* t)
  2509.        (*print-pretty* print-pretty)
  2510.        (*print-length* 50000000)
  2511.        (*package*      (or (and package (find-package package))
  2512.                *package*))
  2513.      (pathname       filename)
  2514.      (form           (MAKE-LET-FORM object-instance 
  2515.                     (get-dump-form object-instance))))
  2516.     (setf (get '.%%SL%%. 'namecounter) 0)
  2517. (with-open-file (stream pathname :direction :output :if-exists if-exists
  2518.             :if-does-not-exist if-does-not-exist)
  2519. (format stream ";;;-*- Mode: Lisp; Base: 10; Syntax: Common-Lisp; Package: ~a -*-~%" (package-name *package*))
  2520.      (format stream "~%~s"
  2521.          `(in-package ',(read-from-string (package-name *package*))))
  2522.      (write-global-header stream 
  2523.               '.%%SL%%. 0
  2524.               *global-instance-count*)
  2525.      (format stream "~%~s" `(setq ,variable ,form)))
  2526.     (format t "~& object saved to file: ~A" pathname)
  2527.     (when compile (format t "~% compiling file ~A" pathname)
  2528.               (compile-file pathname)
  2529.           (format t "~% done compiling file ~A" pathname))))
  2530.  
  2531. ;;;================================
  2532. ;;; ======= dump forms. ===========
  2533. ;;;================================
  2534.  
  2535. (defun STREAM-DUMP-FORM (instance)
  2536. "Very machine dependent! for now, just recognize we got one, return NIL as DUMP FORM."
  2537. (format t "Recognized a stream in save object: ~a.~%" instance)
  2538. NIL)
  2539.  
  2540. (defun STRUCTURED-OBJECT-DUMP-FORM (object)
  2541. "Routine which deals with any potentially circular objects (PCOS)."
  2542. (cond ((null object) NIL)
  2543.       ((%classp object)(class-dump-form object))
  2544.        ((instance-p object)
  2545.      (if (member object *seen* :test #'equal)
  2546.          (symbol-dump-form
  2547.           (nth (position object *seen* :test #'equal) *vars*))
  2548.        (progn (push object *seen*)
  2549.           (setq *vars* (pushsym *vars*))
  2550.           (instance-dump-form object))))
  2551.       ((structure-p object)
  2552.        (if (member object *structs-seen* :test #'equal)
  2553.             (symbol-dump-form (nth (position object *structs-seen*
  2554.                             :test #'equal)
  2555.                       *struct-vars*))
  2556.            (progn (push object *structs-seen*)
  2557.           (setf *struct-vars* (pushsym *struct-vars*))
  2558.           (structure-dump-form object))))
  2559. #|
  2560.       ((vectorp object)
  2561.        (if (member object *vectors-seen* :test #'equal)
  2562.             (progn (symbol-dump-form (nth (position object *vectors-seen*
  2563.                             :test #'equal)
  2564.                       *vector-vars*)))
  2565.        (progn (push object *vectors-seen*)
  2566.           (setf *vector-vars* (pushsym *vector-vars*))
  2567.           (vector-dump-form object))))
  2568.       ((arrayp object)
  2569.        (if (member object *arrays-seen* :test #'equal)
  2570.             (progn (symbol-dump-form (nth (position object *arrays-seen* :test #'equal)
  2571.                   *array-vars*)))
  2572.        (progn (push object *arrays-seen*)
  2573.           (setf *array-vars* (pushsym *array-vars*))
  2574.           (array-dump-form object))))
  2575. |#
  2576.       ((hash-table-p object)
  2577.        (if (member object *htabs-seen* :test #'equal)
  2578.        (symbol-dump-form  (nth (position object *htabs-seen* :test #'equal) *htab-vars*))
  2579.        (progn (push object *htabs-seen*)
  2580.                   (setf *htab-vars* (pushsym *htab-vars*))
  2581.                   (setf *current-htab-size* (or (hash-table-size object) 5000))
  2582.                   (setf *current-htab-rehash-threshold* (or (hash-table-rehash-threshold object) 20))
  2583.                   (setf *current-htab-test* (hash-table-test object))
  2584.                   (setf *current-htab-rehash-size* (or (hash-table-rehash-size object) 67))
  2585.           (htab-dump-form object))))
  2586.       ((circular-list-p object)(circular-list-dump-form object))
  2587.       (T (error "couldnt parse ~a as a structured object!" object))))
  2588.  
  2589. (defun %LOAD-HTAB  (htab &optional lst)
  2590. ""
  2591. (loop
  2592. (when *debug-htab-load* (format t "setting slot ~a to ~a.~%"
  2593.       (first lst)(second lst)))
  2594.       (setf (gethash (pop lst) htab)(pop lst)) 
  2595.     (when (null lst)(return htab))))
  2596.  
  2597. ;;; Map lucid/allegro htab incompatibility of rehash threshold
  2598. ;;; parameter into mutually acceptable values. (i.e. fix bug)
  2599.  
  2600. #+lucid
  2601. (defun SCALE-REHASH-THRESHOLD (num)
  2602. (if (> num 1)(float (/ num 100)) num))
  2603.  
  2604. #+allegro
  2605. (defun  SCALE-REHASH-THRESHOLD (num)
  2606. (if (<= num 1)(* num 100) num))
  2607.  
  2608. #-(or allegro lucid)
  2609. (defun SCALE-REHASH-THRESHOLD (num)
  2610. num)
  2611.  
  2612. (defun MAKEHASH (h &key (test #'eql)
  2613.                     (size 5000)
  2614.                 (rehash-size 67)
  2615.                 (rehash-threshold 0.65)
  2616.                 values)
  2617. ""
  2618. (let ((htab (or h (make-hash-table :test test
  2619.                    :size size
  2620.                    :rehash-size rehash-size
  2621.  :rehash-threshold (scale-rehash-threshold rehash-threshold)))))
  2622. (if (null values) htab
  2623.   (progn (%load-htab htab values) htab))))
  2624.  
  2625. (defun HTAB-DUMP-FORM (htab)
  2626. "Dump for for hash tables.... "
  2627. `(makehash ,(get-instance-label htab)
  2628.        :test ,(get-dump-form (hash-table-test htab))
  2629.         :size ,(get-dump-form (hash-table-size htab))
  2630.         :rehash-size ,(get-dump-form (hash-table-rehash-size htab))
  2631.         :rehash-threshold ,(get-dump-form
  2632.             (hash-table-rehash-threshold htab))
  2633.         :values (LIST ,@(get-htab-values htab))))
  2634.  
  2635. (defun GET-HTAB-VALUES (htab)
  2636. (let ((values nil))
  2637. (maphash #'(lambda (key val)
  2638.          (push (get-dump-form val) values)
  2639.          (push (get-dump-form key) values))
  2640. htab) values))
  2641.  
  2642. (defun PRINT-HTAB (htab)
  2643. (maphash #'(lambda (key val)
  2644. (format t "~%Key: ~a, value=~a.~%" key val))
  2645. htab))
  2646.  
  2647. (defun SIMPLE-ARRAY-DUMP-FORM (array)
  2648. "Numerical arrays are stored using this routine...."
  2649. `(make-array ,(get-dump-form (array-dimensions array))
  2650.          :element-type ',(array-element-type array)
  2651.          :initial-contents ,(list-array array)))
  2652.  
  2653. (defun PACKAGE-DUMP-FORM (package)
  2654. "assume its there in the environment, somewhere."
  2655. (let ((pn (get-dump-form (package-name package))))
  2656. `(FIND-PACKAGE ,pn)))
  2657.  
  2658. (defun STREAM-P (x)
  2659. "Avoids problems with vendor-made type confusion."
  2660. (and (not (%classp x))(streamp x)))
  2661.  
  2662. ;;; the workhorse. NOTE: The case statement is very ORDER-DEPENDENT!
  2663. ;;; If your version of CLOS supports specialization on ALL LISP types,
  2664. ;;; you could write this as a set of DUMP-FORM methods on the LISP types.
  2665. ;;; This has not always been possible with PCL, thus the case statement.
  2666. ;;; NOTE that a CONS is not necessarily a list! CONS-P distinguishes 
  2667. ;;; between items such as (CONS 'A 'B) and (LIST 'A 'B).
  2668. ;;;
  2669. ;;; Notice that this version uses SAFE-CLASS-DUMP-FORM to prevent class
  2670. ;;; definition overwrite. Use CLASS-DUMP-FORM below if you do not want this 
  2671. ;;; behavior!
  2672.  
  2673. (defun INSURE-LIST (X)
  2674. (if (listp x) x (list x)))
  2675.  
  2676. (defun REPEATING-ELEMENT-LIST-P (instance)
  2677. (if (< (length instance) *make-list-length-threshold*) nil
  2678. (let ((test (first instance)))
  2679.   (every #'(lambda (e)(equal e test)) instance))))
  2680.  
  2681. (defun REPEATING-ELEMENT-LIST-DUMP-FORM (instance)
  2682. (let ((length (length instance))
  2683.       (form (get-dump-form (first instance))))
  2684.   `(MAKE-LIST ,length :initial-element ,form)))
  2685.  
  2686. (defun REC-LIST-DUMP-FORM (l)
  2687. `(LIST ,@(%rec-list-dump-form l)))
  2688.  
  2689. (defun %REC-LIST-DUMP-FORM (l)
  2690. ""
  2691. (cond ((null l) nil)
  2692.       ((not (listp (first l)))
  2693.        (cons (get-dump-form (first l))
  2694.          (%rec-list-dump-form (rest l))))
  2695.       (T (cons (%rec-list-dump-form (first l))
  2696.            (%rec-list-dump-form (rest l))))))
  2697.  
  2698. (defun GET-DUMP-FORM (instance)
  2699. "New incarnation of get-dump-form: if the instance is a structured
  2700. object, construct a representation for it anticipating that it might
  2701. be a PCO. NOTE: in MCL Common Lisp, note that STREAMS are implemented as
  2702. CLASSES! This makes it possible to SAVE-OBJECT things like *TERMINAL-IO*!"
  2703.     (cond ((null instance) nil)
  2704.       ((equal instance T) T)
  2705.       ((circular-cons-p instance)(circular-cons-dump-form instance))
  2706.       ((numberp instance) instance)
  2707.       ((or (pathnamep instance)
  2708.            (stringp instance)
  2709.                (keywordp instance)
  2710.                (special-marker-p instance)
  2711.            (characterp instance)) instance)
  2712.           ((packagep instance)(package-dump-form instance))
  2713.       ((quoted-symbol-p instance)(quoted-symbol-dump-form instance))
  2714.       ((symbolp instance)(symbol-dump-form instance))
  2715.       ((and (arrayp instance)(not (pco-p instance)))
  2716.                 (simple-array-dump-form instance))
  2717.       ((vectorp instance)(vector-dump-form instance))
  2718.           ((cons-p instance)(cons-dump-form instance))
  2719.       ((pco-p instance)(structured-object-dump-form instance))
  2720.       ((arrayp instance)(array-dump-form instance))
  2721.       ((functionp instance)(compiled-function-dump-form instance))
  2722.           ((stream-p instance)(stream-dump-form instance))
  2723.           ((readtablep instance)(readtable-dump-form instance))
  2724.       ((repeating-element-list-p instance)
  2725.        (repeating-element-list-dump-form instance))
  2726. ((simple-lex-list-p instance)(simple-list-dump-form instance))
  2727. ((simple-quoted-list-p instance)(simple-quoted-list-dump-form instance))
  2728. ((quoted-list-p instance)(quoted-list-dump-form instance))
  2729. ((simple-list-p instance)(simple-list-dump-form instance))
  2730. ;;;((LISTP instance)(rec-list-dump-form instance))
  2731. ((listp instance)     `(LIST ,@(mapcar #'(lambda (thing)
  2732.               (get-dump-form thing)) instance)))
  2733.       (T (error "could not parse object ~a, of type ~a.~%"
  2734.             instance (type-of instance)))))
  2735.  
  2736. (defun STRIP-PACKAGE (x)
  2737. "strip the package designator off the symbol, return the rest,
  2738. if keyword, return self.."
  2739. (if (keywordp x) x
  2740.   (intern (symbol-name x))))
  2741.  
  2742. (defun SLOT-EXISTS-P-ANY (instance name)
  2743. "returns t if the slotname exists with any package designator."
  2744. (let ((slots (mapcar #'strip-package (all-slotnames instance))))
  2745.   (member (strip-package name) slots :test #'equal)))
  2746.  
  2747. (defun QUOTED-SYMBOL-P (X)
  2748. "Predicate: returns t if the object is a quoted symbol."
  2749. (and (listp x)(equal (first x) 'quote)(symbolp (second x))))
  2750.  
  2751. (defun FLATTEN1 (cells)
  2752. (let ((answer nil))
  2753. (dolist (cell cells answer)
  2754. (setf answer (nconc answer cell)))
  2755. answer))
  2756.  
  2757. (defun UNSAVEABLE-SLOT-TOKEN-P (X)
  2758. "Predicate"
  2759. (equal x *unsaveable-slot-token*))
  2760.  
  2761. (defun GET-SLOT-VALUES (clos-instance)
  2762.   "given a pcl/clos instance,constructs a plist of all the saveable
  2763.    slot/value pairs."
  2764.   (incf *global-instance-count*)
  2765.   (let ((unsaveable (get-unsaveable-slotnames clos-instance)))
  2766. (map-instance #'(lambda (key val)
  2767.   (if (or (member key unsaveable :test #'equal)
  2768.           (member key *global-unsaveable-slotnames* :test #'equal))
  2769.                   (list (make-keyword key) *unsaveable-slot-token*)
  2770.           (list (make-keyword key)(get-dump-form val))))
  2771.           clos-instance
  2772.           :modify nil
  2773.           :concat t)))
  2774.  
  2775. (defun %%GET-DEFSTRUCT-VALUES (clos-instance)
  2776.   "given a pcl/clos instance,constructs a plist of all the saveable
  2777.    slot/value pairs."
  2778.   (incf *global-instance-count*)
  2779. (mapcan #'cdr
  2780. (mapstruct #'(lambda (key val)
  2781.           (list (make-keyword key)(get-dump-form val)))
  2782.           clos-instance
  2783.           :modify nil
  2784.           :concat t)))
  2785.  
  2786. (defun MAKEVAR (&optional (label '.%%SL%%.))
  2787. "makes a new variable for something in the global object hashtable."
  2788. (incf *global-object-count*)
  2789. (newsym label))
  2790.  
  2791. (defun PUSHSYM (list &optional (label '.%%SL%%.))
  2792. "label must match with special-marker-p, and must be upper-case."
  2793.   (push (newsym label) list))
  2794.  
  2795. (defun MAKESYMS (symbol min max &optional (pkg *package*))
  2796. (let ((c min))
  2797.  (progn
  2798.    #+excl (setf excl::*nowarn* T)
  2799. #+symbolics (setf compiler::*suppress-compiler-warnings* T)
  2800. (dotimes (count max)
  2801.  (incf c)
  2802.  
  2803.  (eval `(defvar
  2804. ,(read-from-string (concatenate 'string (format nil "~A" symbol)
  2805.                 (format nil "~A" c))
  2806.   pkg))))
  2807. #+excl (setf excl::*nowarn* NIL)
  2808. #+symbolics (setf compiler::*suppress-compiler-warnings* NIL)
  2809. )))
  2810.  
  2811. (defun WRITE-GLOBAL-HEADER (stream symbol min max
  2812.                   &optional (pkg-name (package-name *package*)))
  2813. (format stream (format nil "~%(EVAL-WHEN (COMPILE LOAD EVAL)
  2814.                        (DATABASE:MAKESYMS '~A ~A ~A ~s))~%"
  2815.                symbol min max pkg-name)))
  2816.  
  2817. (defun NASSOC (key list &key (test #'equal))
  2818. "Given a key and a list, return the thing AFTER that key in the list.
  2819.  Similar to GETF."
  2820.   (let ((where (position key list :test test)))
  2821.     (when where (nth (1+ where) list))))
  2822.  
  2823. (defun %CONS-P (X)
  2824. "Internal dotted list predicate..."
  2825. (and (not (null (list-length x)))
  2826.      (listp x)
  2827.      (atom (cdr (last x)))
  2828.      (not (null (cdr (last x))))))
  2829.  
  2830. (defun CONS-P (x)
  2831.   "ingenious predicate for testing whether something is a cons cell vs. a list.
  2832.    note that this returns nil for (LIST 'A 'B) whereas it returns T for (CONS 'A 'B)."
  2833. (cond ((not (listp x)) NIL)
  2834. ((and (listp x)(null (list-length x))) nil)
  2835. ((or (%cons-p x)(and (listp x)(null (listp (rest x))))) T)
  2836. (T NIL)))
  2837.  
  2838. (defun CONS-DUMP-FORM (item)
  2839.   `(CONS ,(get-dump-form (first item))
  2840.      ,(get-dump-form (rest item))))
  2841.  
  2842. (defun %INSURE-LIST (X)
  2843. (if (listp x) x
  2844.     (list nil x)))
  2845.  
  2846. (defun LIST-ARRAY (array)
  2847. ""
  2848.   (list-array-aux array 0 nil))
  2849.  
  2850. #-(or akcl allegro-v4.0)
  2851. (defun LIST-ARRAY-AUX (array level subscript-list)
  2852. ""
  2853.   (let ((new-level (1+ level))
  2854.     (dims (array-dimensions array)))
  2855.     (loop for i from 0 to (1- (nth level dims))
  2856.       collect
  2857.       (cond ((equal level (1- (length dims)))
  2858.          (let* ((aref-arg-list
  2859.              (cons array (append subscript-list
  2860.                          (list i))))
  2861.             (array-val (apply #'aref aref-arg-list)))
  2862.            (if (numberp array-val) array-val
  2863.              (get-dump-form array-val))))
  2864.         (T (list-array-aux array new-level
  2865.                    (append subscript-list (list i)))))
  2866.       into temp finally (return (append '(list) temp)))))
  2867.  
  2868. #+(or akcl allegro-v4.0)
  2869. (defun LIST-ARRAY-AUX (array level subscript-list)
  2870. ""
  2871.   (let ((new-level (1+ level))
  2872.     (dims (array-dimensions array))
  2873.     (answers nil))
  2874.     (dotimes (i (1- (nth level dims)) answers)
  2875.       (setf answers (append answers (list
  2876.       (cond ((equal level (1- (length dims)))
  2877.          (let* ((aref-arg-list
  2878.              (cons array (append subscript-list
  2879.                          (list i))))
  2880.             (array-val (apply #'aref aref-arg-list)))
  2881.            (if (numberp array-val) array-val
  2882.              (get-dump-form array-val))))
  2883.         (T (list-array-aux array new-level
  2884.            (append subscript-list (list i)))))))))
  2885.  (append '(list) answers)))
  2886.  
  2887. #-(or akcl allegro-v4.0)
  2888. (defun COERCE-2D-ARRAY (2d-array)
  2889.   (let ((rows (array-dimension 2d-array 0))
  2890.     (cols (array-dimension 2d-array 1)))
  2891.     (loop for x from 0 to (1- rows) collect
  2892.       (loop for y from 0 to (1- cols) collect
  2893.         (aref 2d-array x y)) into answers
  2894.       finally (return answers))))
  2895.  
  2896. #+(or akcl allegro-v4.0)
  2897. (defun COERCE-2D-ARRAY (2d-array)
  2898.   (let ((rows (array-dimension 2d-array 0))
  2899.     (cols (array-dimension 2d-array 1))
  2900.     (answers nil)
  2901.     (temp nil))
  2902.     (dotimes (x (1- rows) answers)
  2903. (setf temp nil)
  2904. (setf answers (append answers (list
  2905.        (dotimes (y (1- cols) temp)
  2906.     (setf temp (append temp (list (aref 2d-array x y)))))))))
  2907. answers))
  2908.  
  2909. (defun ARRAY-DUMP-FORM (array)
  2910.   "this function return a make-array form."  
  2911.   (setf *print-array* T)
  2912.    (let ((vals (list-array array)))
  2913.   `(let ((tmp (allocate-array ,(get-dump-form (array-dimensions array))
  2914.            :element-type ',(array-element-type array)
  2915.            :adjustable ,(adjustable-array-p array)
  2916.            :initial-contents ,(get-dump-form vals))))
  2917.      TMP)))
  2918.  
  2919. (defun VECTOR-DUMP-FORM (array)
  2920.   "this function return a make-array form."  
  2921.   (setf *print-array* T)
  2922.    (let ((vals (list-array array)))
  2923.   `(let ((tmp (allocate-array ,(get-dump-form (array-dimensions array))
  2924.            :element-type ',(array-element-type array)
  2925.            :adjustable ,(adjustable-array-p array)
  2926.            :initial-contents ,(get-dump-form vals))))
  2927.      TMP)))
  2928.  
  2929. ;;; HASH TABLES...
  2930.  
  2931. (defun CREATE-HASH-TABLE (&key (test #'eql)
  2932.                    (size 67)
  2933.                    (rehash-size nil)
  2934.                    (rehash-threshold nil))
  2935. (let ((args (remove nil `(:size ,(get-dump-form size)
  2936.      :test ,test
  2937.         ,@(when rehash-size (list :rehash-size (get-dump-form rehash-size)))
  2938.         ,@(when rehash-threshold
  2939.             (list :rehash-threshold (get-dump-form rehash-threshold)))))))
  2940.       (cache-object (apply #'make-hash-table args) :mode :load)))
  2941.  
  2942. (defun MAKE-SYM (x)
  2943. (if (keywordp x)
  2944.     (read-from-string (subseq (symbol-name x) 0))
  2945.   x))
  2946.  
  2947. (defun GET-EVENS (l)
  2948. (let ((answers nil))
  2949. (dotimes (count (1- (length l)) answers)
  2950. (if (evenp count)(push (nth count l) answers)))
  2951. (nreverse answers)))
  2952.  
  2953. (defun GET-ODDS (l)
  2954. (let ((answers nil))
  2955. (dotimes (count (1- (length l)) answers)
  2956. (if (oddp count)(push (nth count l) answers)))
  2957. (nreverse answers)))
  2958.  
  2959. (defun LOAD-HTAB (values &key (test #'eql)
  2960.              (size 67)
  2961.              (rehash-size nil)
  2962.              (rehash-threshold nil))
  2963. ""
  2964. (let ((htab (create-hash-table :test test
  2965.                    :size size
  2966.                    :rehash-size rehash-size
  2967.                    :rehash-threshold rehash-threshold))
  2968. (key nil)(val nil))
  2969. (dolist (cell values)
  2970.     (setf key (first cell))
  2971.     (setf val (eval (second cell)))
  2972.         (setf (gethash key htab) val))))
  2973.  
  2974. ;;;; Arrays & Vectors.
  2975.  
  2976. (defun ALLOCATE-ARRAY (dims &key (element-type t)
  2977.                  (adjustable nil)
  2978.                  (initial-contents nil))
  2979. "Function to allocate an array. No fill-pointer.
  2980.  suggested by kanderson@bbn.com."
  2981. (make-array dims :element-type element-type
  2982.              :initial-contents initial-contents
  2983.          :adjustable adjustable))
  2984.  
  2985.  
  2986. (defun ALLOCATE-VECTOR (dims &key (element-type t)
  2987.                  (adjustable nil)
  2988.                  (fill-pointer nil))
  2989. "Function to allocate an array. suggested by kanderson@bbn.com."
  2990. (make-array dims :element-type element-type
  2991.           :adjustable adjustable
  2992.           :fill-pointer fill-pointer))
  2993.  
  2994. ;;; Compiled functions.
  2995.  
  2996. #+(or :mcl excl)
  2997. (defun GET-COMPILED-FUNCTION-NAME (compiled-function)
  2998. ""
  2999. (let ((ans nil)
  3000.       (strname ""))
  3001. (setq *readtable* (copy-readtable))
  3002. (set-dispatch-macro-character #\# #\' (function pseudo-quote-reader))
  3003. (set-dispatch-macro-character #\# #\< (function pseudo-quote-reader))
  3004. (setf strname (format nil "~S" compiled-function))
  3005. (setq ans (read-from-string (SUBSEQ strname 0 (length strname))))
  3006. (setq *readtable* (copy-readtable nil))
  3007. ans))
  3008.  
  3009. ;;; Massive kludge for encountering READTABLES!!!
  3010.  
  3011. (defun READTABLE-DUMP-FORM (i)
  3012. "Doesnt seem to be a good way to probe the internals of readtables, even
  3013. machine specific ways!!!!"
  3014. (declare (ignore i))
  3015. `(copy-readtable *readtable*))
  3016.  
  3017. ;;; Massive kludge for pre-ansi hash table specs!!!!
  3018.  
  3019. #+lispm
  3020. (defun PARSE-HASH-TABLE-SPEC (htab)
  3021. (let ((ans nil))
  3022. (setq *readtable* (copy-readtable))
  3023. (set-dispatch-macro-character #\# #\' (function pseudo-quote-reader))
  3024. (set-dispatch-macro-character #\# #\< (function pseudo-quote-reader))
  3025. (setq ans (rest (butlast (read-from-string 
  3026.                (concatenate 'string "(" (subseq (format nil "~a" htab) 8) ")")))))
  3027. (setq *readtable* (copy-readtable nil))
  3028. ans))
  3029.  
  3030.  
  3031.  
  3032. #+allegro-v4.0
  3033. (eval-when (load eval compile)
  3034.  
  3035. (defun HASH-TABLE-TEST (htab)
  3036. #'eql)
  3037.  
  3038. (defun HASH-TABLE-SIZE (htab)
  3039. 32)
  3040.  
  3041. (defun PARSE-HASH-TABLE-SPEC (htab)
  3042. (let ((ans nil))
  3043. (setq *readtable* (copy-readtable))
  3044. (set-dispatch-macro-character #\# #\' (function pseudo-quote-reader))
  3045. (set-dispatch-macro-character #\# #\< (function pseudo-quote-reader))
  3046. (setq ans (rest (butlast (read-from-string 
  3047. (concatenate 'string "(" (subseq (format nil "~a" htab) 8) ")")))))
  3048. (setq *readtable* (copy-readtable nil))
  3049. ans))
  3050. ) ;;; end of allegro ver 4.0 eval-when....
  3051.  
  3052. #+rel8
  3053. (defun HASH-TABLE-REHASH-SIZE (x)
  3054. ""
  3055. (future-common-lisp:hash-table-rehash-size x))
  3056.  
  3057. #+rel8
  3058. (defun HASH-TABLE-REHASH-THRESHOLD (x)
  3059. ""
  3060. (future-common-lisp:hash-table-rehash-threshold x))
  3061.  
  3062. #+rel-7-2
  3063. (defun HASH-TABLE-REHASH-SIZE (x)
  3064. ""
  3065. (let ((spec (parse-hash-table-spec x)))
  3066.   (getf spec :rehash-size 32)))
  3067.  
  3068. #+rel-7-2
  3069. (defun HASH-TABLE-REHASH-THRESHOLD (x)
  3070. ""
  3071. (let ((spec (parse-hash-table-spec x)))
  3072.   (getf spec :rehash-threshold 0.5)))
  3073.  
  3074. ;;; Functions and Generic Functions.
  3075.  
  3076. #+:mcl
  3077. (eval-when (load eval compile)
  3078.  
  3079. (defun GENERIC-FUNCTION-NAME (instance)
  3080. (get-compiled-function-name instance))
  3081.  
  3082. (defun GENERIC-FUNCTION-LAMBDA-LIST (gf)
  3083. ""
  3084. (function-lambda-expression gf))
  3085.  
  3086. (defun %GENERIC-FUNCTION-P (X)
  3087. ""
  3088. (ccl::standard-generic-function-p x))
  3089.  
  3090. (defun COMPILED-FUNCTION-DUMP-FORM (X)
  3091. "dump form for hashmark-quote e.g. (FUNCTION name) forms."
  3092.   `(function ,(get-compiled-function-name x)))
  3093.  
  3094. (defun METHOD-SPECIALIZERS (method)
  3095. ""
  3096. (ccl:specializer-direct-generic-functions method))
  3097.  
  3098. (defun METHOD-GENERIC-FUNCTION (gf)
  3099. ""
  3100. (ccl:method-generic-function gf))
  3101.  
  3102. ) ;;; end of MCL function & generic function eval-when!
  3103.  
  3104. (defun GENERIC-FUNCTION-DUMP-FORM (instance)
  3105. "Dump Form for saving out generic functions..."
  3106.      (let ((name (generic-function-name instance))
  3107.        (arglist (generic-function-lambda-list instance))
  3108.        (documentation (%generic-function-documentation instance)))
  3109.        `(OR (FIND-GENERIC-FUNCTION ',name)
  3110.         (DEFGENERIC ,name ,arglist (:DOCUMENTATION ,(or documentation ""))))))
  3111.  
  3112. (defun METHOD-DUMP-FORM (instance)
  3113. "dump form for saving out method objects."
  3114.      (LET* ((name (generic-function-name (method-generic-function instance)))
  3115.         (qualifiers (method-qualifiers instance))
  3116.         (specializers (method-specializers instance)))
  3117.        `(FIND-METHOD (FUNCTION ,name)
  3118.              (LIST ,@qualifiers)
  3119.              (LIST ,@(DO-SPECIALIZERS specializers))
  3120.              NIL)))
  3121.  
  3122. #+excl
  3123. (defun COMPILED-FUNCTION-DUMP-FORM (X)
  3124. "dump form for hashmark-quote e.g. (FUNCTION name) forms."
  3125.   `(function ,(get-compiled-function-name x)))
  3126.  
  3127. #+lispm
  3128. (defun COMPILED-FUNCTION-DUMP-FORM (X)
  3129. "dump form for hashmark-quote e.g. (FUNCTION name) forms."
  3130.   (if (si:lexical-closure-p x) nil
  3131.   `(FUNCTION ,(si:compiled-function-name x))))
  3132.  
  3133. ;;;; PCL/CLOS classes and instances.
  3134. ;;;; NOTE: CLASS DEFINITIONS, WHEN READ IN, WILL OVERWRITE THE
  3135. ;;;; CLASS DEFINITION PREVIOUSLY IN MEMORY. IF YOU DO NOT WANT THIS
  3136. ;;;; TO HAPPEN, REPLACE 'DEFCLASS' BELOW WITH 'FIND CLASS' + the
  3137. ;;;; APPROPRIATE ARGUMENTS!
  3138.  
  3139. (defun SAFE-CLASS-DUMP-FORM (instance)
  3140. "This version of the class-dump-form function WILL NOT overwrite 
  3141.  current class definitions with the same name. It is the one invoked
  3142.  by GET-DUMP-FORM and SAVE-OBJECT."
  3143.   (let* ((name (%class-name instance))
  3144.        (supertypes (get-class-superclasses instance))
  3145.        (slots (generate-class-slot-forms instance))
  3146.        (options (generate-class-options-form instance)))
  3147. `(OR (FIND-CLASS ',name)
  3148.      (DEFCLASS ,name ,supertypes ,slots ,@options))))
  3149.  
  3150. (defun CLASS-DUMP-FORM (instance)
  3151. "This version of the class-dump-form function WILL OVERWRITE 
  3152.  CURRENT CLASS DEFINITIONS WITH THE SAME NAME. Sunstitute a call to
  3153.  this one in GET-DUMP-FORM and SAVE-OBJECT."
  3154.  (let* ((name (%class-name instance))
  3155.        (supertypes (get-class-superclasses instance))
  3156.        (slots (generate-class-slot-forms instance))
  3157.        (options (generate-class-options-form instance)))
  3158.    (if (builtin-class-p instance) `(FIND-CLASS ',name)
  3159.      `(DEFCLASS ,name ,supertypes ,slots ,@options))))
  3160.  
  3161. (defun SYM< (a b)
  3162. "Predicate to see if symbol a is alphabetically before symbol b. T if a is."
  3163. (string< (format nil "~A" A)(format nil "~A" b)))
  3164.  
  3165. (defun SYMF< (a b)
  3166. "Predicate to see if symbol a is alphabetically before symbol b. T if a is."
  3167. (string< (format nil "~A" (FIRST A))(format nil "~A" (first b))))
  3168.  
  3169. (defun GET-ORDERED-SLOT-NAMES (I)
  3170. "Returns a list of the slot names of the instance, alphabetized."
  3171. (cond ((instance-p i)(sort (all-slotnames i) #'sym<))
  3172.       ((structure-p i)#-excl (get-defstruct-slotnames i)
  3173.                       #+excl (%get-defstruct-slotnames i)
  3174.               )
  3175.       (T (error "couldnt parse object ~a!" i))))
  3176.  
  3177. (defun FLATTEN (l)
  3178. ""
  3179. (let ((answers nil))
  3180. (dolist (cell l answers)
  3181.     (setf answers (nconc answers cell)))
  3182. answers))
  3183.  
  3184. (defun PAIR-UP (l)
  3185. ""
  3186. (let ((answers nil))
  3187. (loop (push (list (pop l)(pop l)) answers)
  3188.       (when (null l)(return (reverse answers))))))
  3189.  
  3190. (defun ALPHABETIZE-BY-KEYWORD (lst)
  3191. ""
  3192. (let ((alpha-cells (sort (pair-up lst) #'symf<)))
  3193.   (mapcar #'second alpha-cells)))
  3194.  
  3195. (defun GET-ORDERED-SLOT-VALUES (i)
  3196. "Gets the dump forms out of the instance slot values, then alphabetizes them."
  3197.  (cond ((instance-p i)(alphabetize-by-keyword (get-slot-values i)))
  3198.        ((structure-p i)(%%get-defstruct-values i))
  3199.        (T (error "could not parse object ~a~%" i))))
  3200.  
  3201. (defun %FILL-INSTANCE (i ordered-slot-values)
  3202. "Fills in the slots alphabetically. 
  3203. Assumes the slot values come into the function
  3204.  alphabetically ordered already: Returns the instance object.
  3205. NOTE: modification to deal with unbound slots is included!"
  3206. (if (null ordered-slot-values) i
  3207.   (let ((osv (copy-list ordered-slot-values))
  3208.     (unbound-slot nil)
  3209.     (default-slot nil)
  3210.     (names (get-ordered-slot-names i))
  3211.     (thang nil)
  3212.     (name nil))
  3213. (loop (setf name (pop names))
  3214.       (setf thang (pop osv))
  3215.       (cond ((unbound-slot-token-p thang)
  3216.          (setf unbound-slot T)
  3217.          (setf default-slot NIL))
  3218.         ((unsaveable-slot-token-p thang)
  3219.              (setf default-slot T))
  3220.          ((and thang (symbolp thang))
  3221.           (setf thang `(quote ,thang))
  3222.           (setf unbound-slot NIL)
  3223.           (setf default-slot NIL))
  3224.         (T (setf unbound-slot NIL)
  3225.            (setf default-slot NIL)))
  3226.           ;;; if this slot was marked as unsaveable,
  3227.       ;;; let the value be whatever allocate-instace willed it to be.
  3228.       ;;; if it was unbound when saved, make the new instace slot
  3229.       ;;; unbound, too. if neither, put the supplied slot value from
  3230.           ;;; the file in the slot.
  3231.       (if default-slot NIL ;;; do nothing.
  3232.       (if (not unbound-slot)
  3233.       (cond ((instance-p i)
  3234.       (setf (slot-value i name) thang)) ;;; put the value in.
  3235.       ((structure-p i)(set-defstruct-value i name thang)))
  3236.       (slot-makunbound i name))) ;;; make the slot unbound.
  3237.       (when (and (null names)(null osv))(return i))))))
  3238.  
  3239. #+pcl
  3240. (defmethod %ALLOCATE-INSTANCE (class-object)
  3241. (pcl::allocate-instance class-object))
  3242.  
  3243. #+allegro-v4.0
  3244. (eval-when (load eval compile)
  3245.  
  3246. (defmethod CLOS::ALLOCATE-INSTANCE ((self clos:structure-class) &rest initargs)
  3247. (declare (ignore initargs))
  3248. (allocate-struct (instance-name self)))
  3249.  
  3250. (defmethod %%ALLOCATE-INSTANCE ((self clos:structure-class))
  3251. (allocate-struct (instance-name self)))
  3252.  
  3253. (defmethod %%ALLOCATE-INSTANCE ((self symbol))
  3254. (if (get-symbol-defstruct-spec self)
  3255.     (allocate-struct self)))
  3256.  
  3257. (defmethod CLOS::ALLOCATE-INSTANCE ((self symbol) &rest init-plist)
  3258.     (allocate-struct self))
  3259.  
  3260. (defmethod GET-SYMBOL-DEFSTRUCT-SPEC (self)
  3261. (typep (find-class self nil) 'clos:structure-class))
  3262.  
  3263. ) ;;; end of allegro ver4.0 eval-when...
  3264.  
  3265. #+:mcl
  3266. (defun %STRUCTURE-P (X)
  3267. "predicate, if symbol returns t if it names a struct."
  3268. (and (symbolp x)
  3269.      (equal (class-name (class-of (find-class x nil))) 
  3270.         'STRUCTURE-CLASS)))
  3271.  
  3272. (defun ALLOCATE-HTAB (htab &rest arglist)
  3273. "Allocates the empty husk of a hash table,
  3274.  getting its attributes from the object itself."
  3275. (declare (ignore htab))
  3276. (let ((size (getf arglist :size))
  3277.       (rehash-size (getf arglist :rehash-size))
  3278.                    (test (getf arglist :test))
  3279.                    (rehash-threshold (getf arglist :rehash-threshold)))
  3280. (make-hash-table :size size 
  3281.                  :rehash-size rehash-size 
  3282.                  :rehash-threshold 
  3283.          (scale-rehash-threshold rehash-threshold)
  3284.                  :test test)))
  3285.  
  3286. #+clos
  3287. (defun %ALLOCATE-INSTANCE (class-object &rest htab-plist) 
  3288.   (cond ((equal class-object 'HASH-TABLE)
  3289.      (allocate-htab class-object 
  3290.             :size (getf htab-plist :size
  3291.                     5000)
  3292.             :rehash-size (getf htab-plist :rehash-size 67)
  3293. :rehash-threshold (getf htab-plist :rehash-threshold 0.67)
  3294.             :test (getf htab-plist :test #'eql)))
  3295.         ((%structure-p class-object)
  3296.      #-excl (clos::allocate-instance class-object)
  3297.      #+allegro-v4.0(%%allocate-instance class-object)
  3298.      #+allegro-v4.1(clos::allocate-instance class-object)
  3299.      )
  3300.         (T (when *debug-instance-storage*
  3301.  (format t "now trying to allocate an instance for ~a!" class-object))
  3302.            (when (symbolp class-object)
  3303.          (setf class-object (find-class class-object nil)))
  3304.            (when class-object (clos::allocate-instance class-object)))))
  3305.  
  3306. #+clos
  3307. (defun FILL-INSTANCE (new vals)
  3308. "New: allocates an instance given classname, the vals are the alphabetized list of
  3309.  slot values extracted from the target instance. returns the newly filled in instance."
  3310.   (%fill-instance new vals)
  3311.   new)
  3312.  
  3313. #+pcl
  3314. (defun FILL-INSTANCE (classname vals)
  3315. "New: allocates an instance given classname, the vals are the alphabetized list of
  3316.  slot values extracted from the target instance. returns the newly filled in instance."
  3317. (let* ((new (pcl::allocate-instance (find-class classname))))
  3318.   (%fill-instance new vals)
  3319.   new))
  3320.  
  3321. ;;; ========= user defined dump forms ==========
  3322.  
  3323. (defun INSTANCE-DUMP-FORM (instance)
  3324. "NEW VERSION. ATTEMPTS TO DEAL WITH SIRCULAR SLOT VALUE REFS,
  3325. Basic dump form for clos/pcl instances. checks if the instance has a custom
  3326.  dump form, binds it to a generated symbol name, recursively expands the
  3327.  instances contents."
  3328. (declare (special tmp))
  3329.   (if (has-dump-form-p (instance-name instance))
  3330.       `(setq ,(get-instance-label instance) ,(funcall #'(lambda (x)
  3331.                        (get-dump-form x))
  3332.                        instance))
  3333.  `(fill-instance ,(get-instance-label instance)
  3334.          (LIST ,@(get-ordered-slot-values instance)))))
  3335.  
  3336. ;;; symbols.
  3337.  
  3338. (defun SPECIAL-MARKER-P (X &optional (label ".%%SL%%."))
  3339.  
  3340. "label must match with pushsym, and must be upper-case."
  3341.   (search label (format nil "~A"  x) :test #'equal))
  3342.  
  3343. (defun SYMBOL-DUMP-FORM (instance)
  3344. "Better bolder symbol saving formula which includes the package data implicitly."
  3345. (if (null instance) NIL
  3346. (if (special-marker-p instance) instance
  3347. (read-from-string (format nil "~a" (concatenate 'string "'"
  3348.                  (package-name (symbol-package instance)) "::"
  3349.                           (symbol-name instance)))))))
  3350.  
  3351. (defun SIMPLE-QUOTED-LIST-P (X)
  3352. "Predicate, if somethings a quoted list...."
  3353. (and (not (cons-p x))
  3354.      (listp x)
  3355.      (not (circular-list-p x))
  3356.      (not (every #'null x))
  3357.      (every #'(lambda (sub)(and (not (special-marker-p sub))
  3358.                 (or (numberp sub)
  3359.                    (characterp sub)
  3360.                    (stringp sub)
  3361.                    (symbolp sub))))
  3362.  
  3363.         x)))
  3364.  
  3365.  
  3366. (defun QUOTED-LIST-P (x)
  3367. "Predicate, if somethings a quoted list...."
  3368. (and (not (cons-p x))
  3369.      (listp x)
  3370.      (not (circular-list-p x))
  3371.      (not (every #'null x))
  3372.      (every #'(lambda (sub)(or (numberp sub)
  3373.                    (characterp sub)
  3374.                    (stringp sub)
  3375.                    (AND (symbolp sub)
  3376.                    (not (special-marker-p sub)))
  3377.                    (quoted-list-p sub)))
  3378.         x)))
  3379.  
  3380. (defun SIMPLE-QUOTED-LIST-DUMP-FORM (x)
  3381. (let ((it (quoteit x)))
  3382. `(QUOTE (,@it))))
  3383.  
  3384. (defun QUOTEIT (l)
  3385. (cond ((null l) nil)
  3386.       ((null (first l))
  3387.        (cons nil (quoteit (rest l))))
  3388.       ((equal (first l) T)
  3389.        (cons t (quoteit (rest l))))
  3390.       ((not (listp (first l)))
  3391.        (cons (get-dump-form (first l))(quoteit (rest l))))
  3392.       ((simple-quoted-list-p (first l))
  3393.        (cons (simple-quoted-list-dump-form (first l))
  3394.          (quoteit (rest l))))
  3395.       (T (cons (quoted-list-dump-form (first l))
  3396.            (quoteit (rest l))))))
  3397.  
  3398. #|
  3399. (defun QUOTED-LIST-P (x)
  3400. "Predicate, if somethings a quoted list...."
  3401. (and (not (cons-p x))
  3402.      (listp x)
  3403.      (not (circular-list-p x))
  3404.      (not (every #'null x))
  3405.      (every #'symbolp x)))
  3406. |#
  3407.  
  3408. (defun QUOTED-LIST-DUMP-FORM (instance)
  3409. "If something is a quoted list, put the quote at the right place."
  3410. (let ((it (quoteit instance)))
  3411. `(QUOTE ,instance)))
  3412.  
  3413. ;;;; ===================================== TESTS ============================================
  3414.  
  3415. ;;; *** NASTY TEST SUITE: A collection of self-referencing consolas that put this code to the test!
  3416.  
  3417. (setf *print-circle* t)
  3418.  
  3419. (setq l '(a b c d e f))
  3420.  
  3421. (setf (third l) (cdr l))
  3422.  
  3423. (defstruct (boo (:type list))  x y)
  3424.  
  3425. (setq b (make-boo
  3426.       :x (vector 1 2 (make-hash-table) 4)
  3427.       :y (make-boo :x '(#\a #c(1.7 4.99)))))
  3428.  
  3429. (defstruct boo1  x y)
  3430.  
  3431. (setq b1 (make-boo1
  3432.       :x (vector 1 2 (make-hash-table) 4)
  3433.       :y (make-boo :x '(#\a #c(1.7 4.99)))))
  3434.  
  3435. #+lispm
  3436. (defvar *nasty-path* "e:>kerry>")
  3437.  
  3438. #+:mcl
  3439. (defvar *nasty-path* "Macintosh HD:")
  3440.  
  3441. #+:mcl
  3442. (setf *nasty-path* "Macintosh HD:")
  3443.  
  3444. ;;; UNIX BOX PATH:
  3445.  
  3446. #+(or excl akcl lucid)
  3447. (defvar *nasty-path* "/users/kerry/save-object/tests/")
  3448.  
  3449. ;;; Test Classes:
  3450.  
  3451. (defclass SLOTLESS ()
  3452.   ((a)(B)(c)(d)(e)))
  3453.  
  3454. (defvar *test-cons-save* (cons 10 (cons (make-hash-table :test #'equal)
  3455.                     (make-array 20))))
  3456.  
  3457. (defun TEST-CONS-SAVE ()
  3458. ""
  3459. (save-object *test-cons-save* "cons-save-test.lisp"))
  3460.  
  3461. (defun TEST-UNBOUND-SLOT-SAVE ()
  3462. ""
  3463. (let ((inst (make-instance 'slotless)))
  3464. (save-object inst "slotless-test-save.lisp")))
  3465.  
  3466. (defun NASTY-PATH (filename)
  3467. ""
  3468. (concatenate 'string *nasty-path* filename))
  3469.  
  3470. (defun LESS-NASTY-INSTANCE-TEST ()
  3471. "One instance with one self-reference."
  3472. (let ((a (make-instance 'test)))
  3473.   (setf (slot-value a 'a) a)
  3474.   (setf (slot-value a 'b) a)
  3475.   (save-object a (NASTY-PATH "little-instance.lisp"))))
  3476.  
  3477. (defvar *a)
  3478. (defvar *b)
  3479. (defvar *c)
  3480. (defvar *d)
  3481. (defvar *the-nasties* nil "stored here for later review.")
  3482.  
  3483. (defclass BOGON ()
  3484. ((name :initarg :name
  3485.        :accessor bogon-name
  3486.        :documentation ""))
  3487. (:default-initargs :name "")
  3488. (:documentation ""))
  3489.  
  3490. (defmethod INITIALIZE-INSTANCE :AFTER ((self bogon) &rest plist)
  3491. (declare (ignore plist))
  3492. (push self *the-nasties*))
  3493.  
  3494. #-lispm
  3495. (defmethod PRINT-OBJECT ((self bogon) stream)
  3496. (with-slots (name) self
  3497. (format stream "#<Test Instance ~A>" name)))
  3498.  
  3499. #+lispm
  3500. (defmethod PRINT-OBJECT ((self bogon) stream)
  3501. (with-slots (name) self
  3502. (format stream "#<~A: ~A>" name (si:%pointer self))))
  3503.  
  3504. (defclass TEST (bogon)
  3505. ((a :initarg :a)
  3506.  (b :initarg :b)
  3507.  (c :initarg :c)
  3508.  (name :initarg :name))
  3509. (:default-initargs :a nil
  3510.            :b nil
  3511.            :c nil
  3512.            :name "")
  3513. (:documentation "Simple test class for the examples below."))
  3514.  
  3515. (defstruct foo a b c)
  3516.  
  3517. (defun NASTY-STRUCT-TEST ()
  3518. (let ((a (make-foo)))
  3519. (setf (foo-a a) a)
  3520. (save-object a (NASTY-PATH "nnn.lisp"))))
  3521.  
  3522. (defun GET-NASTY (filename)
  3523. (concatenate 'string *nasty-path* filename ".lisp"))
  3524.  
  3525. #+lispm
  3526. (defun NASTY-ARRAY-TEST ()
  3527. ""
  3528. (let ((them! nil))
  3529. (tv:noting-progress ("Nasty Array Allocation!")
  3530.  (setf them! (LIST (make-array '(50 20 36) :element-type 'float
  3531.              :initial-element PI)
  3532.            (make-array 10 :initial-contents (make-list 10
  3533.                                :initial-element "STRINGS!"))
  3534.            (make-array '(21 16 33 4) :element-type '(unsigned-byte 32)
  3535.                    :initial-element 1024)
  3536.            (make-array '(20 20) :element-type 'character
  3537.                    :initial-element #\!)))
  3538. )
  3539. (tv:noting-progress ("Nasty Array Storage!")
  3540. (save-object them! (NASTY-PATH "horrid-arrays.lisp")))))
  3541.  
  3542. #-lispm
  3543. (defun NASTY-ARRAY-TEST ()
  3544. ""
  3545. (let ((them! (LIST (make-array '(50 20 36) :element-type 'float
  3546.              :initial-element pi)
  3547.            (make-array 10 :initial-contents (make-list 10
  3548.                            :initial-element "STRINGS!"))
  3549.            (make-array '(21 16 33 4) :element-type '(unsigned-byte 32)
  3550.                    :initial-element 666)
  3551.            (make-array '(20 20) :element-type 'character
  3552.                    :initial-element #\!))))
  3553. (save-object them! (NASTY-PATH "horrid-arrays.lisp"))))
  3554.  
  3555. (defun NASTY-INSTANCE-TEST ()
  3556.   ""
  3557. (setf *a (make-instance 'test :name "A")
  3558.        *b (make-instance 'test :name "B")
  3559.        *c (make-instance 'test :name "C"))
  3560. (setf (slot-value *a 'a) *b)
  3561. (setf (slot-value *a 'b) *c)
  3562. (setf (slot-value *b 'a) *a)
  3563. (setf (slot-value *b 'b) *c)
  3564. (setf (slot-value *c 'a) *b)
  3565. (setf (slot-value *c 'b) *a)
  3566. (save-object *a (NASTY-PATH "nasty-inst.lisp")))
  3567.  
  3568. (defun BOBS-INSTANCE-TEST ()
  3569.   " A ----> B ----> C ----> D
  3570.     ^       ^       |       V
  3571.     |-------+--------       |
  3572.             |----------------   "
  3573.  
  3574. (setf *a (make-instance 'test :name "A")
  3575.        *b (make-instance 'test :name "B")
  3576.        *c (make-instance 'test :name "C")
  3577.        *d (make-instance 'test :name "D"))
  3578.  
  3579. (setf (slot-value *a 'a) *b)
  3580. (setf (slot-value *b 'a) *c)
  3581. (setf (slot-value *c 'a) *d)
  3582. (setf (slot-value *c 'b) *a)
  3583. (setf (slot-value *d 'a) *b)
  3584.  
  3585. (save-object *a (NASTY-PATH "bobtest.lisp")))
  3586.  
  3587. (defun BOBS-INSTANCE-TEST-2 ()
  3588.  
  3589. "BACKPOINTERS ON ALL THE PREVIOUS EXAMPLES
  3590.  (two links on each node: twice as many as before, ten.)
  3591.  
  3592.     A <---> B <---> C <---> D
  3593.     ^       ^       V       V
  3594.     V--<>---+-------^       |
  3595.             V----<>---------^   "        
  3596.  
  3597. (setf *a (make-instance 'test :name "A")
  3598.        *b (make-instance 'test :name "B")
  3599.        *c (make-instance 'test :name "C")
  3600.        *d (make-instance 'test :name "D"))
  3601.  
  3602. (setf (slot-value *a 'a) *b)
  3603. (setf (slot-value *a 'b) *c)
  3604.  
  3605. (setf (slot-value *b 'a) *c)
  3606. (setf (slot-value *b 'b) *d)
  3607. (setf (slot-value *b 'c) *a)
  3608.  
  3609. (setf (slot-value *c 'a) *d)
  3610. (setf (slot-value *c 'b) *a)
  3611. (setf (slot-value *c 'c) *d)
  3612.  
  3613. (setf (slot-value *d 'a) *b)
  3614. (setf (slot-value *d 'b) *c)
  3615. (save-object *a (NASTY-PATH "bobtest2.lisp")))
  3616.  
  3617. (defvar *nasty-hash-tables* nil)
  3618.  
  3619. (defun NASTY-HASH-CHAIN-TEST ()
  3620. " Makes a nested hash table net like this:
  3621.  
  3622.      a->b  b->c  c->d  d->e   e->a
  3623.     a-----b-----c-----d----->e----->|
  3624.     ^                               v
  3625.     |<---------------------<---------
  3626.       e->a      e->a       e->a   e->"
  3627.  
  3628. (setf *nasty-hash-tables* nil)
  3629. (let* ((a (make-hash-table))
  3630.        (b (make-hash-table))
  3631.        (c (make-hash-table))
  3632.        (d (make-hash-table))
  3633.        (e (make-hash-table)))
  3634. (pushnew a *nasty-hash-tables*)
  3635. (pushnew b *nasty-hash-tables*)
  3636. (pushnew c *nasty-hash-tables*)
  3637. (pushnew d *nasty-hash-tables*)
  3638. (pushnew e *nasty-hash-tables*)
  3639. (setf (gethash 'a->b b) a)
  3640. (setf (gethash 'b->a a) b)
  3641. (setf (gethash 'b->c c) b)
  3642. (setf (gethash 'c->b b) c)
  3643. (setf (gethash 'c->d d) c)
  3644. (setf (gethash 'd->e e) d)
  3645. (setf (gethash 'e->a a) e)
  3646. (save-object a (NASTY-PATH "qhash.lisp"))))
  3647.  
  3648. (defun NASTIER-STRUCT-TEST ()
  3649. (save-object b1 (NASTY-PATH "b1-test.lisp")))
  3650.  
  3651. (defun GET-HTAB-KEYS (htab)
  3652. (let ((values nil))
  3653. (maphash #'(lambda (key val)
  3654.          (push key values))
  3655. htab)
  3656. values))
  3657.  
  3658. (defvar *test-struct-form*
  3659. '(SETQ *DB-INPUT* (LET* ((.%%SL%%.1 (%ALLOCATE-INSTANCE 'BOO1))) (FILL-STRUCT .%%SL%%.1 '(BOO1)))))
  3660.  
  3661. (defvar *test1* (list (make-instance 'test)
  3662.               (make-hash-table :test #'eq)
  3663.               (list (make-foo)
  3664.                 (make-foo)
  3665.                 (list (make-instance 'test)
  3666.                   #c(0 1)
  3667.                   (make-foo)))))
  3668.  
  3669. ;;; END OF THE NASTIES.
  3670.  
  3671. ;;; end of file.
  3672.